Dynamisch Programmeren
Dynamisch Programmeren
Dynamisch Programmeren
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
<strong>Dynamisch</strong> <strong>Programmeren</strong><br />
extreem ver doorgedreven recursie: om een groot probleem op te<br />
lossen, splitsen we het in kleinere problemen die onafhankelijk van<br />
elkaar opgelost kunnen worden<br />
wanneer we niet precies weten welke kleinere problemen op te lossen,<br />
berekenen we ze allemaal en bewaren de antwoorden voor later gebruik<br />
‘programmeren’ is hier in de betekenis van ‘het proces van beperkingen<br />
formuleren zodanig dat de methode toepasbaar is’<br />
1
soorten problemen:<br />
• het is niet altijd mogelijk om oplossingen voor kleinere problemen<br />
te combineren en tot een oplossing voor een groter probleem te<br />
komen<br />
• het aantal op te lossen kleine problemen kan onaanvaardbaar groot<br />
zijn<br />
2
Knapzak probleem<br />
zoek een combinatie van objecten die in een knapzak passen zodanig<br />
dat de waarde maximaal is<br />
toepassingen: vervoersmaatschappij (laden van vrachtwagen, schip,<br />
vliegtuig, ...)<br />
3
for (j = 1; j
Fig.1 Voorbeeld van een knapzak probleem<br />
5
cost[i] is de hoogste waarde die met knapzak capaciteit i verkregen<br />
kan worden; best[i] is het laatst toegevoegde item om dat maximum<br />
te bekomen<br />
de inhoud van de optimale knapzak kan berekend worden met de best<br />
array<br />
6
Fig.2 Oplossing van het knapzak probleem<br />
7
Eig.1 De tijd nodig voor het oplossen van het knapzak probleem met<br />
dynamisch programmeren is evenredig met NM (N: soorten objecten;<br />
M: grootte van de knapzak).<br />
het probleem is dus eenvoudig op te lossen als M niet groot is<br />
als M of de groottes, waarden van de objecten reële getallen zijn ipv<br />
gehele getallen werkt het niet (fundamenteel probleem)<br />
voordeel: vroeger opgeloste deelproblemen moeten niet opnieuw bekeken<br />
worden;<br />
dynamisch programmeren vindt een optimale oplossing<br />
8
Matrix Chain Product<br />
klassieke toepassing: minimaliseren van de hoeveelheid rekenwerk nodig<br />
om een reeks matrices van verschillende grootte te vermenigvuldigen<br />
de volgorde waarin de matrices vermenigvuldigd worden bepaalt het<br />
aantal bewerkingen<br />
aantal mogelijkheden om N matrices te vermenigvuldigen: Catalaans<br />
getal is ongeveer 4 N−1 /N √ πN<br />
9
⎛<br />
⎜<br />
⎝<br />
a11 a12<br />
a21 a22<br />
a31 a32<br />
a41 a42<br />
⎞<br />
⎟<br />
⎠<br />
b11 b12 b13<br />
b21 b22 b23<br />
⎛<br />
⎝ c11<br />
c21<br />
c31<br />
⎞<br />
⎠ d11 d12<br />
e11 e12<br />
e21 e22<br />
f11 f12 f13<br />
f21 f22 f23<br />
10
de oplossing met dynamisch programmeren is ‘bottom-up’:<br />
er is maar 1 manier om M1 te vermenigvuldigen met M2, en 1 manier<br />
om M2 met M3 te vermenigvuldigen; die kosten worden bewaard<br />
we berekenen ook de manier om opeenvolgende triples te vermenigvuldigen,<br />
gebruik makend van wat al berekend is<br />
11
for (i = 1; i
voor 1 ≤ j ≤ N − 1 vinden we de minimale kost om MiM i+1...M i+j te<br />
berekenen<br />
optimale volgorde, afgeleid uit cost en best:<br />
13
Fig.3 Oplossing van het matrix chain probleem<br />
14
order(int i, int j)<br />
{<br />
if (i == j)<br />
cout >> name(i);<br />
else<br />
{<br />
cout >> ’(’;<br />
order(i, best[i][j]-1);<br />
cout >> ’*’;<br />
order(best[i][j], j);<br />
cout >> ’)’;<br />
}<br />
}<br />
15
Eig.2 <strong>Dynamisch</strong> programmeren lost het ‘matrix chain product’ probleem<br />
op in tijd evenredig met N 3 en met geheugen evenredig met<br />
N 2 .<br />
16
Optimale Binaire Zoekbomen<br />
naar sommige sleutels wordt veel vaker gezocht dan naar andere; het<br />
is best om de vaakst gezochte bovenaan in de zoekboom te plaatsen<br />
aan elke knoop van de binaire boom kennen we een integer toe die<br />
evenredig is met de frequentie van zoeken<br />
17
Fig.4 Optimale binaire zoekboom<br />
18
kost van de boom berekenen door de frequentie van elke knoop te<br />
vermenigvuldigen met de afstand tot de wortel en alles op te tellen<br />
(gewogen interne padlengte)<br />
het verschil met Huffman codering is dat het hier wel belangrijk is om<br />
de volgorde te respecteren; in binaire bomen zijn alle knopen links<br />
van de wortel kleiner enz.<br />
beste manier is voor elke j, toenemend van 1 tot N − 1 om een<br />
deelboom op te bouwen met Ki, K i+1, ...K i+j voor 1 ≤ i ≤ N − j<br />
19
for ( i =1; i
Fig.5 Binaire zoekboom met frequenties<br />
21
Eig.3 De dynamic programming methode om een optimale binaire<br />
boom te vinden gebeurt in tijd evenredig met N 3 en gebruikt ruimte<br />
evenredig met N 2 .<br />
22
Tijd en ruimte<br />
toepassingen van dynamisch programmeren kunnen compleet verschillende<br />
tijd en ruimte nodig hebben afhankelijk van de hoeveelheid informatie<br />
over kleine deelproblemen<br />
voor de knapzak is de benodigde ruimte evenredig met de grootte van<br />
de knapzak; voor andere problemen is N 2 ruimte nodig<br />
23