* Числа на Фибоначи: F(0) = F(1) = 1 и F(i) = F(i -1) + F(i - 2) за i > 1.
Експоненциална сложност - многократно извикване на функцията с един и същи аргумент!unsigned long fib(unsigned n)
{ if (n < 2) return 1;
return fib(n - 1) + fib(n - 2);
}
* Динамично програмиране - със запомняне на вече пресметнатите стойности:
Линейна сложност - всяка стойност се пресмята само веднаж.#include <stdio.h>
#define MAX 256
unsigned n = 10;
unsigned long m[MAX + 1];
unsigned long fibMemo(unsigned n)
{ if (n < 2) m[n] = 1;
else if (0 == m[n]) m[n] = fibMemo(n - 1)+ fibMemo(n - 2);
return m[n];
}
int main()
{ memset(m, 0, MAX*sizeof(*m));
scanf("%u", &n);
printf("\n%u-тото число на Фибоначи e", %lu", n, fibMemo(n));
return 0;
}
Нека C(n, k) е биномният
коефициент
"n над k" или комбинации без повторения от n
елемента
k-ти клас.
Общата формула е: C(n, k)
= n!/((n - k)! k!), а от триъгълника на Паскал
имаме
и рекурентна формула:
* Рекурсивен неефективен алгоритъм:
unsigned long binom(unsigned n, unsigned k)
{ if (k > n) return 0;
if (k == 0 || k == n) return 1;
return binom(n - 1, k - 1) + binom(n - 1, k);
}
* Динамично програмиране - със запомняне на вече пресметнатите стойности. Не е необходимо да се пази цялата таблица C(n, k), а само един ред от таблицата - предишния.
Пример: n = 5, k = 3; C(5,3) = 10.#define MAX 200
unsigned long m[MAX];
unsigned long binomDynam(unsigned n, unsigned k)
{ unsigned i, j;
for (i = 0; i <= n; i++)
{ m[i] = 1;
if (i > 1)
{ if (k < i - 1) j = k; else j = i - 1;
for (; j >= 1; j--) m[j] += m[j - 1];
}
}
return m[k];
}
i |
k<i-1 |
начално j | m 0 1 2 3 4 |
0 |
- |
- | 1 1 1 1 1 |
1 |
- |
- | 1 1 1 1 1 |
2 |
3<2-1 |
1 |
1 2 1 1 1 |
3 |
3<3-1 |
2 | 1 3 3 1 1 |
4 |
3<4-1 |
3 | 1 4 6 4 1 |
5 |
3<5-1 |
3 |
1 5 10 10 5 |
Дадени са две редици (от числа или символи):
Търси се най-дълга редица Z = (z1, z2, ..., zk), която е подредица на X и Y едновременно. Z е подредица на X, ако Z може да бъде получена чрез премахване на (0 или няколко) членове на X.
Най-напред ще търсим само дължината на най-дългата
обща подредица.
Ще
приложим
метода на динамичното оптимиране, като F(i, j) е
търсената
дължина за първите i члена на редицата X и първите
j
члена на редицата Y. Очевидно
F(i,0) = 0 за всяко
i, F(0, j) = 0 за всяко j.
F(i,
j) = F(i -1, j -1) + 1 за xi
=
yj,
F(i, j) = max {F(i -1,
j), F(i,
j -1)} в противен случай.
Намираме последователно стойностите на F(i,
j) и последната намерена стойност F(m,n) е решението
на задачата.
Намирането на една най-дълга подредица (може да не е една) става по същия начин, като тръгваме от последния елемент и следим откъде идва максималната стойност.
9// lsc.c
#include <stdio.h>
#include <string.h>
#define MAXN 100
#define MAX(a,b) (((a)>(b)) ? (a) : (b))
char F[MAXN][MAXN];
const char x[MAXN] = "acbcacbcaba";
const char y[MAXN] = "abacacacababa";
unsigned m,n;
/*
"acb cacbcaba " "a cbcac bcaba"
"a bacacacababa" "abacacacab aba"
solution "a b cac caba " "a c cac b aba"
*/
unsigned lcs_len(void)
{ unsigned i,j;
for (i=0; i<=m; i++) F[i][0]= 0;
for (j=0; j<=n; j++) F[0][j]= 0;
for (i=1; i<=m; i++)
for (j=1; j<=n; j++)
if (x[i-1] == y[j-1]) F[i][j]=F[i-1][j-1]+1;
else F[i][j] = MAX(F[i-1][j], F[i][j-1]);
return F[m][n];
}
void print(unsigned i, unsigned j)
{ if (i == 0 || j == 0) return;
if (x[i-1] == y[j-1])
{ print(i-1,j-1);
printf("%c", x[i-1]);
}
else if (F[i][j] == F[i-1][j]) print(i-1,j);
else print(i,j-1);
}
int main()
{ m = strlen(x);
n = strlen(y);
printf("%u\n", lcs_len());
print(m,n);
return 0;
}
|
|
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
|
"" |
a | c |
b |
c |
a |
c |
b |
c |
a |
b |
a |
|
0 |
"" |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
a |
0 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 | 1 |
|
2 |
b |
0 |
1 |
1 |
2 |
2 |
2 |
2 |
2 |
2 |
2 |
2 |
2 |
3 |
a |
0 |
1 |
1 |
2 |
2 |
3 |
3 |
3 |
3 |
3 |
3 |
3 |
4 |
c |
0 |
1 |
2 |
2 |
3 |
3 |
4 |
4 |
4 |
4 |
4 |
4 |
5 |
a |
0 |
1 |
2 |
2 |
3 |
4 |
4 |
4 |
4 |
5 |
5 |
5 |
6 |
c |
0 |
1 |
2 |
2 |
3 |
4 |
5 |
5 |
5 |
5 |
5 |
5 |
7 |
a |
0 |
1 |
2 |
2 |
3 |
4 |
5 |
5 |
5 |
6 |
6 |
6 |
8 |
c |
0 |
1 |
2 |
2 |
3 |
4 |
5 |
5 |
6 |
6 |
6 |
6 |
9 |
a |
0 |
1 |
2 |
2 |
3 |
4 |
5 |
5 |
6 |
7 |
7 |
7 |
10 |
b |
0 |
1 |
2 |
3 |
3 |
4 |
5 |
6 |
6 |
7 |
8 |
8 |
11 |
a |
0 |
1 |
2 |
3 |
3 |
4 |
5 |
6 |
6 |
7 |
8 |
9 |
12 |
b |
0 |
1 |
2 |
3 |
3 |
4 |
5 |
6 |
6 |
7 |
8 |
9 |
13 |
a |
0 |
1 |
2 |
3 |
3 |
4 |
5 |
6 |
6 |
7 |
8 |
9 |