9. Динамично оптимиране - I

Задача за раницата [8.2.1]

Дадена е раница с вместимост M килограма и N предмета, всеки от които се характеризира с две числа - тегло mi и стойност ci. Да се избере такова множество от предмети, чиято стойност е максимална, а сумата от теглата не надвишава M.

Дефинираме рекурентна целева функция:

F(0) = 0;  F(i) = max { cj + F(i - mj),  j = 1, 2, ..., Nmj ≤ i }, i > 0

Методът на динамичното оптимиране изисква последователно пресмятане на стойностите на F(i), като за това пресмятане се използват вече пресметнатите стойности за по-малки i.

Програма на С++ за решаване на задачата.

Да разгледаме примера:

N = 8;
index  1  2  3  4  5  6  7  8
m[8] 3, 7, 6, 1, 2, 4, 5, 5
c[8] 5, 3, 9, 1, 1, 2, 5, 2
M = 8;

Fn[0] = 0;
Fn[1] = max{c[4]+Fn[0]} = 1;
set[1][4]=1; set[1] = {0,0,0,1,0,0,0}

Fn[2] = max{c[4]+Fn[1], c[5]+Fn[0]} = 1
set[2][5]=1; set[2] = {0,0,0,0,1,0,0}

Fn[3] = max{c[1]+Fn[0], c[4]+Fn[2], c[5]+Fn[1]} =
max{5 +0, 1 +1, 1 +1} = 5
set[3][1]=1; set[3] = {1,0,0,0,0,0,0}

Fn[4] = max{c[1]+Fn[1], c[4]+Fn[3], c[5]+Fn[2], c[6]+Fn[0]} =
max{5 +1, 1 +5, 1 +1, 2 +0} = 6
set[4][1]=1; set[4] = {1,0,0,1,0,0,0}

Fn[5] = max{c[1]+Fn[2],c[4]+Fn[4],c[5]+Fn[3],c[6]+Fn[1],c[7]+Fn[0],c[8]+Fn[0]} =
max{5 +1, 1 +6, 1 +5, 2 +1, 5 +0, 2 +0} = 6
set[5][1]=1; set[5] = {1,0,0,0,1,0,0}

Fn[6] = max{c[1]+Fn[3],c[3]+Fn[0],c[4]+Fn[5],c[5]+Fn[4],c[6]+Fn[2],c[7]+Fn[2],c[8]+Fn[1]} =
max{5 +5, 9 +0, 1 +5, 1 +6, 2 +1, 5 +1, 2 +1} = 9
set[6][3]=1; set[6] = {0,0,1,0,0,0,0}

Fn[7] = max{c[1]+Fn[4],c[2]+Fn[0],c[3]+Fn[1],c[4]+Fn[6],c[6]+Fn[5],c[7]+Fn[2],c[8]+Fn[2]} =
max{5 +6, 5 +0, 9 +1, 1 +9, 2 +6, 5 +1, 2 +1} = 10
set[7][3]=1; set[7] = {0,0,1,1,0,0,0}

Fn[8] = max{c[1]+Fn[5],c[2]+Fn[1],c[3]+Fn[2],c[4]+Fn[7],c[6]+Fn[4],c[7]+Fn[3],c[8]+Fn[3]} =
max{5 +6, 5 +1, 9 +1, 1 +10, 2 +6, 5 +1, 2 +1} = 10
set[8][3]=1; set[8] = {0,0,1,0,1,0,0}

Варианти на алгоритъма за решаване на задчата:

Варианти на задачата за раницата:


"Лесна" задача

Зайче в беда

                Веднъж малкото бяло зайче, гонено от един ловец попаднало в лабиринт, които имал форма на квадратна дъска N x N. В него чакал големия лош вълк, които предварително изкопал дупки, където зайчето да падне и той да го хване по-лесно. В последния момент зайчето с ужас разбрало, че може да се движи само в посока надолу и надясно и че изхода от лабиринта е чак в долния десен ъгъл на дъската.

                Зайчето трябвало да разбере каква е вероятността да излезе от лабиринта без да падне в някоя дупка. За целта трябвало да изчисли броя пътища от входа до изхода на лабиринта, като успяло да се снабди с картата на този лабиринт. Картата е зададена с размер N, като местата на дупките са означени с 0, а проходимите места с 1. Напишете програма, която пресмята търсения брой пътища.


Братска подялба [8.2.2]

Двама братя трябва да си поделят комплект от n подаръка. Всеки подарък има стойност цяло положително число. Да се разделят подаръците на две части със стойности a и b, така, че |a - b| да има най-малка стойност.

Нека сумата от стойностите на всички подаръци е p. Правим масив c с p елемента, като c[i] = 1, ако i може да се получи като сума на някои подаръци, в противен случай c[i] = 0. Решението на задачата ще бъде индексът на най-близкия до p/2 ненулев елемент на c.

Нека стойностите на подаръците да са:
3, 2, 3, 2, 2, 77, 89, 23, 90, 11

Решение.
a = 136, b = 166

alanbob.cpp