Esta é uma pré-visualização de arquivo. Entre para ver o arquivo original
Algoritmos matemáticos básicos que todo cara da computação deveria
saber
Algoritmo 1 : Conversão da base 10 para a base b
Primeiramente, vamos começar com o algoritmo de mudança de base numérica. Para
converter um número da base 10 para uma base b qualquer podemos efetuar
sucessivas divisões do número pela base b; o resto das divisões serão os dígitos do
número da nova base só que na ordem inversa.
Calcular número de dígitos d de número n na base b
d = log b n =
void base(int n, int b, int novo[], int * tam){
int k;
k = *tam = floor( log(n)/log(b) + 0.5) + 1;
while( n > 0){
k--;
novo[k] = n % b;
n = n / b;
}
}
Complexidade O(logbn)
Algoritmo 2: Conversão de um número da base b para a base 10
Podemos converter um número da base b para a base 10 através desta
expressão:
N = an.b
n + .... + a2.b
2 + a1.b
1 + a0.b
0
Vamos reescrever essa expressão da seguinte maneira:
N =b( an.b
n-1 + .... + a2.b
1 + a1.b
0 ) + a0.b
0
N =b( b( an.b
n-2 + .... + a2.b
0 )+ a1.b
0 ) + a0.b
0
N =b( b( an.b
n-2 + .... + a2.b
0 )+ a1.b
0 ) + a0.b
0
N =b(...b(b(an ) + an-1)...) + a0.b
0
Agora, podemos calcular o número na base b realizando n multiplicações.
N = 100112
A[0] = 1
A[1] = 0
A[2] = 0
A[3]= 1
A[4] = 1
X[0] = A[0]
X[i] = X[i-1]*B + A[i]
N = X[4]
X[0] = 1
X[1] = 2 + 0 = 2
X[2] = 4 + 0 = 4
X[3] = 8 + 1 = 9
X[4] = 18 +1 = 19
int base(int b, int novo[] , int tam){
int n,i;
n = novo[0];
for(i=1;i<tam;i++){
n = n*b;
n = n + novo[i];
}
return n;
}
Complexidade O(n) multiplicações e soma
Máximo divisor Comum de a e b
Encontrar o maior número d que divide a e b simultaneamente.
Sabemos que se d divide a e d divide b então d < a e d < b;
Algoritmo 1: Força bruta
int mdc1(int a,int b){
int i,d;
d = a < b ? a : b;
for(i=d;i>=1;i--){
if(a%i==0 && b%i==0) return i;
}
}
Complexidade O( min(a,b) )
Algoritmo 2: Busca Binária
int mdc2(int a,int b){
int i,f,meio,d;
d = a < b ? a : b;
i = 1;
f = d;
while( i < f ){
meio = (i + f) / 2;
if( a%meio ==0 && b%meio==0) i = meio;
else f = meio-1;
}
return i;
}
Complexidade O( lg min(a,b) )
Algoritmo 3: Algoritmo de Euclides:
int mdc3(int a,int b){
if(b==0) return a;
else return mdc3(b,a%b);
}
O número de chamadas deste algoritmo é proporcional ao número de
Fibonacci pelo seguinte teorema:
Teorema:
Se a > b >= 0 e euclides(a,b) executa k >= 1 chamadas recursivas então a
>= Fk+2 e b >= Fk+1.
Suponha que a e b são dois números de Fibonacci consecutivos então
O número de chamadas recursivas de EUCLIDES(Fk+2,Fk+1) é igual ao
número de chamadas recursivas EUCLIDES(Fk+1, Fk+2 mod Fk+1) + 1.
Temos que Fk+2 = Fk+1 + Fk mod Fk+1 = Fk. . Logo, EUCLIDES(Fk+1, Fk+2 mod
Fk+1) = EUCLIDES(Fk+1, Fk) com k -1 chamadas recursivas.
O número de chamadas recursivas de EUCLIDES(Fk+2,Fk+1) é k-1 +1.
Este teorema pode ser utilizado para estimar um limite superior para o
número de chamadas recursivas do algoritmo.
Complexidade O(k) , b >= Fk+1
Algoritmo 4: Mdc Binário
int gcd(int u, int v){
if( u == v ) return u;
if( u == 0 ) return v;
if( v == 0 ) return u;
if(u%2 == 0){ // se u é par
if(v%2 == 0) // u and v são pares
return (2*gcd(u/2, v/2));
else // u é par and v é impar
return gcd(u/2, v);
}
else if(v%2 == 0) // u é impar e v é par
return gcd(u, v/2);
else{ // ambos são impares
if(u>=v)
return gcd((u-v)/2, v);
else
return gcd((v-u)/2, u);
}
}
Usando operações com bits:
int gcd(int u, int v){
if( u == v ) return u;
if( u == 0 ) return v;
if( v == 0 ) return u;
if(u & 1==0){ // se u é par
if( v & 1 == 0) // u and v são pares
return (gcd(u >> 1, v >> 1) << 1);
else // u é par and v é impar
return gcd(u >> 1, v);
}
else if(v & 1 ==0) // u é impar e v é par
return gcd(u, v >> 1);
else{ // ambos são impares
if(u>=v)
return gcd((u-v) >> 1, v);
else
return gcd((v-u) >> 1, u);
}
}
Algoritmo : Calcular ab
Podemos definir o algoritmo ab diretamente da seguinte definição
recursiva:
def exp(a,b):
if b==0: return 1
else: return a*exp(a,b-1)
O número de multiplicações é definido pela seguinte relação de
recorrência:
T(n) = T(n-1) +1
T(0) = 0
Aplicando o método da substituição, temos:
T(n) = T(n-1) + 1
T(n-1) = T(n-2)+1
...
T(n-(k-1))=T(n-k)+1
Simplificando as equações, temos:
T(n) = T(n-1) + 1
T(n-1) = T(n-2)+1
...
T(n-(k-1))=T(n-k)+1
T(n)=T(n-k)+k
Tome n-k=0 isso implica que k=n.
T(n) = T(0)+n
T(n) = n
Podemos reduzir o número de multiplicações, alterando a definição
recursiva para a seguinte maneira:
def fastexp(a,b):
if b==0 : return 1
else:
if b%2==0:
x = fastexp(a,b/2)
return x*x
else:
return a*fastexp(a,b-1)
O número de multiplicações é definido pela seguinte relação de
recorrência supondo que n é uma potência de 2:
T(n) = T(n/2) +1
T(1) = 1
Aplicando o método da substituição, temos:
T(n) = T(n/2) + 1
T(n/2) = T(n/4)+1
...
T(n/2k-1)=T(n/2k)+1
Simplificando as equações, temos:
T(n) = T(n/2) + 1
T(n/2) = T(n/4)+1
...
T(n/2k-1)=T(n/2k)+1
T(n)=T(n/2k)+k
Tome n/2k=1 isso implica que k=log 2n.
T(n) = T(1)+ log 2n
T(n) = log 2n + 1
Algoritmo: Número de Fibonacci
A definição recursiva do algoritmo fibonacci é a seguinte:
O algoritmo iterativo pode ser definido da seguinte maneira:
def fibo_iterativo(n):
if n <= 2: return 1
else:
ant = 1
atual = 1
i = 2
while i < n:
prox = ant+atual
ant = atual
atual = prox
i = i+1
return prox
Complexidade O(n)
Podemos calcular o número de fibonacci a partir da
seguinte equação matricial:
Utilizando a exponenciação rápida para realizar a
multiplicação matricial podemos obter o seguinte
algoritmo:
def fastfibo(n):
[a,b,c,d] = matriz_exp(1,1,1,0,n)
return b
def matriz_exp(a,b,c,d,n):
if n==1:
return [a,b,c,d]
if n==0:
return [1,0,0,1]
if(n%2==1):
[a1,b1,c1,d1] = matriz_exp(a,b,c,d,n-1)
return [a*a1+b*c1,a*b1+b*d1,a1*c+d*c1,c*b1+d1*d]
else:
[a1,b1,c1,d1] = matriz_exp(a,b,c,d,n/2)
return [a1*a1+b1*c1,a1*b1+b1*d1,a1*c1+d1*c1,c1*b1+d1*d1]
Complexidade O(log2n)