* Числа на Фибоначи: 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) е решението
на задачата.
Намирането на една най-дълга подредица (може да не е една) става по същия начин, като тръгваме от последния елемент и следим откъде идва максималната стойност.
|
|
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 |