Динамическое программирование


Пример. Сумму s = 20 можно выдать 4 способами



бет2/6
Дата19.07.2016
өлшемі0.53 Mb.
#208895
түріРешение
1   2   3   4   5   6

Пример. Сумму s = 20 можно выдать 4 способами:


1) 20 2) 10 + 10 3) 10 + 5 + 5 4) 5 + 5 + 5 +5




k \ n

0

5

10

15

20

начало

0

1

0

0

0

0

c = 5

1

1

1

1

1

1

c = 10

2

1

1

2

2

3

c = 20

3

1

1

2

2

4

Остальные номиналы не повлияют на результат для суммы в 20 центов.

Реализация. Ячейка mas[i] будет содержать количество способов, которыми можно выдать сумму i. Размер массива установим MAX = 30001. Номиналы монет (в центах) занесем в массив coins. Динамически пересчитываем массив mas для каждого номинала (всего 11 номиналов) согласно соотношению, приведенному в анализе алгоритма.

#include

#include
const int MAX = 30001;

double v;

int i,j,n;

long long mas[MAX];

int coins[11] = {5,10,20,50,100,200,500,1000,2000,5000,10000};
void main(void)

{

memset(mas,0,sizeof(mas)); mas[0] = 1;



for(i=0;i<11;i++)

{

for(j=coins[i];j

mas[j] += mas[j-coins[i]];

}
Читаем входные суммы v, преобразовываем их в целое число центов n и печатаем результат mas[n] в соответствии с требуемым форматом.


while(scanf("%lf",&v),v>0)

{

n = (int)(v*100+0.1);



printf("%6.2lf%17lld\n",v,mas[n]);

}

}


4. Оптимальное умножение матриц [Вальядолид, 348]. Обозначим через Aij произведение матриц Ai * Ai+1 * … * Aj-1 * Aj (1  ijn), через m[i, j] минимальное количество умножений, необходимое для вычисления Aij. Стоимость вычисления всего произведения A1n будет храниться в m[1, n]. Значения m[i, i] = 0, поскольку Aii = Ai и для его нахождения вычисления не нужны.

Количество столбцов матрицы Ai равно количеству строк матрицы Ai+1. Это значение хранится в p[i]. Количество строк матрицы А1 находится в p[0], а количество столбцов An – в p[n].

Предположим, что при оптимальной расстановке скобок в произведении Ai * … * Aj последней операцией умножения будет (Ai * … * Ak ) * (Ak+1 * … * Aj). Значение m[i, j] равно сумме минимальной стоимости вычислений Aik и Ak+1j плюс стоимость умножения этих двух матриц:

m[i, j] = m[i, k] + m[k+1, j] + p[i-1] * p[k] * p[j]

При этом число k может принимать только ji разных значений: i, i + 1, …, j – 1. Поскольку только одно из них является оптимальным, то необходимо перебрать все эти значения и выбрать наилучшее. Получим рекуррентную формулу:

m[i, j] =



Для запоминания оптимального умножения положим s[i, j] = k, если при оптимальном вычислении Ai * … * Aj последней операцией будет умножение Ai * … * Ak на Ak+1 * … * Aj.

Пример. Рассмотрим третий тест. Данные о размерах входных матриц сохраняются в массиве p:

30

35

15

5

10

20

25

Минимальная стоимость вычисления матриц Aij хранится в ячейках массива m[i, j]:

i \ j

1

2

3

4

5

6

1

0

15750

7875

9375

11875

15125

2




0

2625

4375

7125

10500

3







0

750

2500

5375

4










0

1000

3500

5













0

5000

6
















0

Соответствующие значения матрицы s:

i \ j

1

2

3

4

5

6

1

0

1

1

3

3

3

2

0

0

2

3

3

3

3

0

0

0

3

3

3

4

0

0

0

0

4

5

5













0

5

6
















0

Для умножения шести входных матриц достаточно выполнить m[1,6] = 15125 операций умножения. Оптимальная последовательность умножений имеет вид:

A16 = (s[1,6] = 3) = A13 * A46 =

(s[1,3] = 1, s[4,6] = 5) = (A11 * A23) * (A45 * A66) =

(s[2,3] = 2, s[4,5] = 4) = (A11 * (A22 * A33 ) ) * ((A44 * A55) * A66) =

(A1 * (A2 * A3 ) ) * ((A4 * A5) * A6)

Реализация. Переменная INF обозначает число «бесконечность», MAX – 1 содержит максимально возможное число матриц в произведении. Объявим строковый массив Stroka, в котором храним числа от 0 до 10 в виде строк. Объявим массивы m, s, p, описанные выше. В переменной Answer будем накапливать результат.

#define INF 0x3F3F3F3F

#define MAX 11

string Stroka[11] = {"0","1","2","3","4","5","6","7","8","9","10"};

int m[MAX][MAX], s[MAX][MAX], p[MAX];

string Answer;


Функция Mult находит минимальное количество умножений, необходимое для вычисления Aij = Ai * Ai+1 * … * Aj-1 * Aj, которое сохраняем в ячейке m[i, j].
int Mult(int i, int j)

{

int k, temp;



if (m[i][j] == INF)

for (k = i; k <= j - 1; k++)

{

temp = Mult(i,k) + Mult(k+1,j) + p[i-1] * p[k] * p[j];



if (temp < m[i][j])

{

m[i][j] = temp; s[i][j] = k;



}

}

return m[i][j];



}
Функция Print(i, j) выводит оптимальное произведение матриц Ai * Ai+1 * … * Aj-1 * Aj согласно формату вывода.
string Print(int i, int j)

{

if (i == j) return "A" + Stroka[i];



return "(" + Print(i,s[i][j]) + " x " + Print(s[i][j]+1,j) + ")";

}
Основной цикл программы. Переменная cs содержит номер теста.


cs = 1;

while(scanf("%d",&n),n>0)

{
Присвоим всем ячейкам массива m значения «бесконечность».
memset(m,0x3F,sizeof(m));
Читаем размеры входных матриц, сохраняем их в массиве p. Положим m[i, i] = 0.
for(i = 1; i <= n; i++)

{

scanf("%d %d",&p[i-1],&p[i]); m[i][i] = 0;



}
Вычисляем результат – ищем оптимальное произведение матриц A1 * A2 * … * An-1 * An.
Mult(1,n);
Выводим номер теста cs. Если n = 1, то перемножать нечего и следует вывести строку "(A1)". Иначе вызываем функцию Print(1,n), которая возвращает строку, содержащую последовательность оптимального произведения матриц.
printf("Case %d: ",cs++);

if (n == 1) Answer = "(A1)"; else Answer = Print(1,n);


Выводим результат – строку Answer.
printf("%s\n",Answer.c_str());

}
5. Наибольшая общая подпоследовательность [Вальядолид, 10405]. Пусть f(n, m) – длина максимальной общей подпоследовательности последовательностей x1x2xn и y1y2ym.

Если xn  ym, то f(n, m) = max( f(n, m - 1), f(n - 1, m) );

Если xn = ym, то f(n, m) = 1 + f(n - 1, m - 1);

Значения f(n, m) будем хранить в массиве c[0..1000, 0..1000], где c[0, i] = c[i, 0] = 0.

Каждая следующая строка массива с[i, j] вычисляется через предыдущую. Поэтому для нахождения ответа достаточно держать в памяти только две строки длины 1000.




Достарыңызбен бөлісу:
1   2   3   4   5   6




©dereksiz.org 2024
әкімшілігінің қараңыз

    Басты бет