Relações de recorrência
Relações de recorrência aparecem recorretemente :) em computação. Podemos encontrar o n-ésimo termo de uma relação de recorrência em O(n) utilizando programação dinâmica:
*Construindo uma solução bottom-up com resultados pré-calculados.
*Utilizando memorização.
Podemos também resolver relações de recorrência através de álgebra linear. Uma relação recorrência pode ser vista como uma sequência de vetores definida por uma equação matricial x(i+1) = M x(i) para uma matriz constante M.
Considere a relação de recorrência que define a sequência de Fibonacci.
F(i+1) = F(i) + F(i-1)
F(i+1) =[a b][F(i) ]
F(i) [c d][F(i-1)]
aF(i) + bF(i-1) = F(i+1)
a=b=1
F(i) + F(i-1) = F(i+1)
cF(i) + dF(i-1) = F(i)
c = 1 , d=0
F(i)=F(i)
f(0) = 0
f(1) = 1
[1 1][f(1)=1]=[f(2)=1]
[1 0][f(0)=0] [f(1)=1]
[1 1][f(2)=1]=[f(3)=2]
[1 0][f(1)=1] [f(2)=1]
[1 1][f(3)=2]=[f(3)=3]
[1 0][f(2)=1] [f(2)=2]
([1 1] )^n [F(1)] = [F(n+1)]
([1 0] ) [F(0)] [F(n) ]
Podemos calcular o n-ésimo termo da sequência de fibonacci utilizando exponenciação de matriz com complexidade $O(log_2 n)$ da seguinte maneira:
Considere a seguinte propriedade para n >= 1:
M^n = [F(n+1) F(n)]
[F(n) F(n-1)]
n=1
[1 1]
[1 0]
é válido
Passo de indução:
M^(n+1) = M*M^n
[1 1][F(n+1) F(n) ]=[F(n+2) F(n+1)]
[1 0][F(n) F(n-1)] [F(n+1) F(n) ]
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <map>
#include <vector>
#include <iostream>
using namespace std;
template <typename T>
T** multiplica(T **a, T **b, int n){
int i,j,k;
T** c;
c = (T **)malloc(n*sizeof(T *));
for(i=0;i<2;i++)
c[i] = (T *)malloc(n*sizeof(T));
for(i=0;i<n;i++){
for(j=0;j<n;j++){
c[i][j] = T();
for(k=0;k<n;k++){
c[i][j] += a[i][k]*b[k][j];
}
}
}
return c;
}
template <typename T>
T** exp(T **a,int n, int m){
int i,j;
T ** c;
T ** b;
c = (T **)malloc(n*sizeof(T *));
for(i=0;i<2;i++)
c[i] = (T *)malloc(n*sizeof(T));
b = (T **)malloc(n*sizeof(T *));
for(i=0;i<2;i++)
b[i] = (T *)malloc(n*sizeof(T));
if(m==0){
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(i==j) b[i][j] = (T)1;
else b[i][j] = (T)0;
}else if(m==1){
for(i=0;i<n;i++)
for(j=0;j<n;j++)
b[i][j] = a[i][j];
}else if(m%2==0){
c = exp(a,n,(int)m/2);
b = multiplica(c,c,n);
}else if(m%2==1){
c = exp(a,n,m-1);
b = multiplica(c,a,n);
}
free(c);
return b;
}
template <typename T>
void show(T** M, int n){
int i,j;
for(i=0;i<n;i++){
for(j=0;j<n;j++){
cout << M[i][j] << " ";
}
cout << "\n";
}
}
int main(){
int i;
int ** M;
M = (int **)malloc(2*sizeof(int *));
for(i=0;i<2;i++)
M[i] = (int *)malloc(2*sizeof(int));
M[0][0] = 1;
M[0][1] = 1;
M[1][0] = 1;
M[1][1] = 0;
show(M,2);
int **Mn;
int n;
n=1;
Mn = exp(M,2,n);
printf("n=1\n");
printf("F[%d]=%d\n",n+1,Mn[0][0]);
printf("F[%d]=%d\n",n,Mn[0][1]);
printf("F[%d]=%d\n\n",n-1,Mn[1][1]);
n = 2;
Mn = exp(M,2,n);
printf("n=2\n");
printf("F[%d]=%d\n",n+1,Mn[0][0]);
printf("F[%d]=%d\n",n,Mn[0][1]);
printf("F[%d]=%d\n\n",n-1,Mn[1][1]);
n=10;
Mn = exp(M,2,n);
printf("n=10\n");
printf("F[%d]=%d\n",n+1,Mn[0][0]);
printf("F[%d]=%d\n",n,Mn[0][1]);
printf("F[%d]=%d\n\n",n-1,Mn[1][1]);
}
1 1
1 0
n=1
F[2]=1
F[1]=1
F[0]=0
n=2
F[3]=2
F[2]=1
F[1]=1
n=10
F[11]=89
F[10]=55
F[9]=34
Referências:
http://en.wikipedia.org/wiki/Recurrence_relation
http://comeoncodeon.wordpress.com/2011/05/08/recurrence-relation-and-matrix-exponentiation/
Nenhum comentário:
Postar um comentário