26.02.2013 Views

Algoritmen en Complexiteit - Universiteit van Amsterdam

Algoritmen en Complexiteit - Universiteit van Amsterdam

Algoritmen en Complexiteit - Universiteit van Amsterdam

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>Algoritm<strong>en</strong></strong> <strong>en</strong> <strong>Complexiteit</strong><br />

Le<strong>en</strong> Tor<strong>en</strong>vliet<br />

6 februari 2013


c○ Alle recht<strong>en</strong> zijn voorbehoud<strong>en</strong> aan de auteur. Verspreiding door middel <strong>van</strong> druk, e-mail, ftp, http, of<br />

andere media is toegestaan mits de volledige onveranderde tekst wordt overgedrag<strong>en</strong>.<br />

Aan de tekst kan verder ge<strong>en</strong> <strong>en</strong>kel recht word<strong>en</strong> ontle<strong>en</strong>d <strong>en</strong> ge<strong>en</strong> <strong>en</strong>kele impliciete of explicite garantie<br />

wordt gegev<strong>en</strong> voor de correctheid <strong>en</strong>/of volledigheid <strong>van</strong> de tekst. Comm<strong>en</strong>taar <strong>en</strong> correctievoorstell<strong>en</strong> zijn<br />

uiteraard <strong>van</strong> harte welkom op mijn e-mailadres le<strong>en</strong>@sci<strong>en</strong>ce.uva.nl. 6 februari 2013


Inhoudsopgave<br />

Voorwoord 7<br />

I <strong>Algoritm<strong>en</strong></strong> 9<br />

1 Voorspel 13<br />

1.1 Inleiding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />

1.2 Analyse <strong>van</strong> <strong>Algoritm<strong>en</strong></strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />

1.2.1 Met<strong>en</strong> is wet<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />

1.2.2 Voorspell<strong>en</strong> is beter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />

1.2.3 Somm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />

1.3 Asymptotische Gr<strong>en</strong>z<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

1.3.1 Notatie voor de <strong>Complexiteit</strong> <strong>van</strong> <strong>Algoritm<strong>en</strong></strong> . . . . . . . . . . . . . . . . . . . . . . . 24<br />

1.3.2 Somm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

1.4 Wiskundige Hulpmiddel<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

1.4.1 Inductie <strong>en</strong> Recursie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

1.4.2 Recurr<strong>en</strong>te betrekking<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />

1.4.3 Reeks<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />

1.4.4 Reeks<strong>en</strong> <strong>en</strong> Integral<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32<br />

1.4.5 Somm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33<br />

2 Techniek<strong>en</strong> 35<br />

2.1 Gulzige <strong>Algoritm<strong>en</strong></strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35<br />

2.1.1 Geld Wissel<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36<br />

2.1.2 Knapsack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36<br />

2.1.3 Graf<strong>en</strong>: kortste pad<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

2.1.4 Graf<strong>en</strong>: opspann<strong>en</strong>de bom<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38<br />

2.1.5 Scheduling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40<br />

2.1.6 Somm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43<br />

2.2 Verdeel <strong>en</strong> Heers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44<br />

2.2.1 Matrixverm<strong>en</strong>igvuldiging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45<br />

2.2.2 Zoek<strong>en</strong> <strong>en</strong> sorter<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46<br />

2.2.3 Somm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50<br />

2.3 Dynamisch Programmer<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50<br />

2.3.1 Dynamisch programmer<strong>en</strong> <strong>en</strong> Knapsack . . . . . . . . . . . . . . . . . . . . . . . . . . 51<br />

2.3.2 Tekstwijzig<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52<br />

2.3.3 Kortste pad<strong>en</strong> 2: Floyd-Warshall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />

2.3.4 Matrixverm<strong>en</strong>igvuldiging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54<br />

2.3.5 Somm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56<br />

3


3 Graf<strong>en</strong>algoritm<strong>en</strong> 57<br />

3.1 Zoek<strong>en</strong> in Graf<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57<br />

3.1.1 Depth First Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57<br />

3.1.2 Breadth First Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60<br />

3.2 Kortste pad<strong>en</strong> 3: De A ∗ algoritme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60<br />

3.3 Netwerk<strong>en</strong> <strong>en</strong> Strom<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62<br />

3.3.1 Min Cut Max Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62<br />

3.3.2 Gelaagde Netwerk<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64<br />

3.4 Toepassing<strong>en</strong> <strong>van</strong> Network Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66<br />

3.4.1 Perfect Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66<br />

3.4.2 Connectivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66<br />

3.4.3 Matrixsomm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67<br />

3.4.4 Somm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67<br />

4 Numerieke <strong>Algoritm<strong>en</strong></strong> 69<br />

4.1 De Euclidische Algoritme <strong>en</strong> Uitbreiding<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69<br />

4.1.1 De Uitgebreide Euclidische Algoritme <strong>en</strong> Invers<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . 70<br />

4.1.2 somm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70<br />

4.2 Verm<strong>en</strong>igvuldiging <strong>van</strong> Grote Getall<strong>en</strong>, DFT . . . . . . . . . . . . . . . . . . . . . . . . . . . 71<br />

4.2.1 Inleiding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71<br />

4.2.2 De eerste algoritm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71<br />

4.3 Betere algoritm<strong>en</strong> voor verm<strong>en</strong>igvuldiging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72<br />

4.3.1 De kampio<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73<br />

4.3.2 Getall<strong>en</strong> als polynom<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73<br />

4.3.3 Complexe n-de machts e<strong>en</strong>heidswortels . . . . . . . . . . . . . . . . . . . . . . . . . . . 75<br />

4.3.4 De Fast-Fourier transform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75<br />

4.3.5 De inverse Fourier transform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76<br />

4.4 Snelle Machtsverheffing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77<br />

4.4.1 somm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78<br />

4.5 Cryptografie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78<br />

4.5.1 Private Key . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79<br />

4.5.2 Sleutel Del<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79<br />

4.5.3 Public Key . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80<br />

4.5.4 Priemgetall<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81<br />

4.5.5 somm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81<br />

4.6 Beveiliging <strong>van</strong> gegev<strong>en</strong>s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81<br />

4.6.1 Id<strong>en</strong>tificatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82<br />

4.6.2 Commitm<strong>en</strong>t . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82<br />

4.6.3 somm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82<br />

II <strong>Complexiteit</strong>stheorie 83<br />

5 Modell<strong>en</strong> voor Berek<strong>en</strong>ing 87<br />

5.1 Redelijke Machinemodell<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87<br />

5.1.1 De Random Access Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87<br />

5.1.2 De Turing Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89<br />

5.1.3 Simulaties tuss<strong>en</strong> RAMS <strong>en</strong> Turingmachines . . . . . . . . . . . . . . . . . . . . . . . . 93<br />

5.2 Onredelijke Machinemodell<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94<br />

5.2.1 Onbegr<strong>en</strong>sd Parallellisme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94<br />

5.2.2 Oneerlijk tell<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95<br />

5.2.3 Somm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96<br />

4


6 C<strong>en</strong>trale <strong>Complexiteit</strong>sklass<strong>en</strong> 97<br />

6.1 Polynomiale <strong>en</strong> Expon<strong>en</strong>tiële Tijd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98<br />

6.1.1 De Universele Turing Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98<br />

6.1.2 Het Padding Lemma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100<br />

6.1.3 P �= EXP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100<br />

6.1.4 somm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101<br />

6.2 NP Problem<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102<br />

6.3 Het Nondeterministische Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104<br />

6.4 Reductie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105<br />

6.5 NP-volledigheid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106<br />

6.5.1 Meer NP-volledige problem<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109<br />

6.5.2 Besliss<strong>en</strong>, Optimalisatie <strong>en</strong> Zelfreduceerbaarheid . . . . . . . . . . . . . . . . . . . . . 121<br />

6.6 Somm<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124<br />

6.7 NP-problem<strong>en</strong> <strong>en</strong> de Praktijk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125<br />

6.7.1 SAT, KNAPSACK, <strong>en</strong> VC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125<br />

6.7.2 E<strong>en</strong> b<strong>en</strong>adering voor TSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126<br />

6.7.3 Branch <strong>en</strong> Bound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127<br />

III Extra Onderwerp<strong>en</strong> 129<br />

7 Meer <strong>Complexiteit</strong>sklass<strong>en</strong> 133<br />

7.1 Geheug<strong>en</strong>begr<strong>en</strong>sde Klass<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133<br />

7.2 PSPACE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133<br />

7.2.1 Volledige Problem<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134<br />

7.2.2 Andere PSPACE Volledige Problem<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . 135<br />

7.3 LOGSPACE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138<br />

7.3.1 Complete Problem<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139<br />

7.4 Interactieve Bewijz<strong>en</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140<br />

7.5 Zero Knowledge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140<br />

7.6 IP=PSPACE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />

7.6.1 IP ⊆ PSPACE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142<br />

7.6.2 PSPACE ⊆ IP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142<br />

A Begripp<strong>en</strong>lijst 145<br />

5


Voorwoord<br />

Sinds 1983 geef ik jaarlijks het vak <strong>Complexiteit</strong>stheorie aan de <strong>Universiteit</strong> <strong>van</strong> <strong>Amsterdam</strong>. Soms in<br />

combinatie met Automat<strong>en</strong>theorie, soms in combinatie met <strong>Algoritm<strong>en</strong></strong>, <strong>en</strong> de laatste tijd ook als rechtstreeks<br />

vervolg op het college Datastructur<strong>en</strong>. Er zijn vele, vele boek<strong>en</strong> over algoritm<strong>en</strong>, goede <strong>en</strong> minder goede. Zo<br />

nu <strong>en</strong> dan vraagt e<strong>en</strong> stud<strong>en</strong>t mij of er niet e<strong>en</strong> goed boek over algoritm<strong>en</strong> in het Nederlands geschrev<strong>en</strong> is<br />

<strong>en</strong> mijn antwoord is dan: “Voorzover ik weet niet.” Natuurlijk is de “markt” voor Nederlandse boek<strong>en</strong> over<br />

wet<strong>en</strong>schappelijke onderwerp<strong>en</strong> sowieso klein <strong>en</strong> is de neiging om e<strong>en</strong> boek te schrijv<strong>en</strong> in het Nederlands<br />

over e<strong>en</strong> onderwerp waarover zoveel goede boek<strong>en</strong> al beschikbaar zijn niet erg groot. Toch is het idee niet<br />

zo bijzonder. Als we naar onze oosterbur<strong>en</strong> kijk<strong>en</strong> dan zi<strong>en</strong> we dat het daar heel gebruikelijk is om colleges<br />

in boekvorm te noter<strong>en</strong> <strong>en</strong> vervolg<strong>en</strong>s uit te br<strong>en</strong>g<strong>en</strong> zodat deze boek<strong>en</strong> door de stud<strong>en</strong>t<strong>en</strong> gebruikt kunn<strong>en</strong><br />

word<strong>en</strong>. Nu de druk op stud<strong>en</strong>t<strong>en</strong> om snel door de studie he<strong>en</strong> te kom<strong>en</strong> ook in ons land steeds groter wordt<br />

<strong>en</strong> bov<strong>en</strong>di<strong>en</strong> is afgesprok<strong>en</strong> dat in de bachelorfase <strong>van</strong> de studie het Nederlands de voertaal is, lijkt het<br />

ge<strong>en</strong> grote stap om ook het studiemateriaal in het Nederlands aan te bied<strong>en</strong>. Vandaar deze tekst. Of het<br />

e<strong>en</strong> “goed” boek wordt, of is geword<strong>en</strong>, zoals door de stud<strong>en</strong>t in kwestie werd gevraagd laat ik graag aan de<br />

lezer. Het boek is in grote lijn<strong>en</strong> de neerslag <strong>van</strong> e<strong>en</strong> college algoritmiek <strong>en</strong> bespreekt de onderwerp<strong>en</strong> die<br />

ik graag in zo’n college voorbij laat kom<strong>en</strong>. Ik gebruik de tekst voortdur<strong>en</strong>d tijd<strong>en</strong>s het college <strong>en</strong> de tekst<br />

wordt ook aangepast naar aanleiding <strong>van</strong> kritische opmerking<strong>en</strong> <strong>van</strong> de stud<strong>en</strong>t<strong>en</strong>.<br />

De tekst bestaat uit drie del<strong>en</strong>. In het eerste deel besprek<strong>en</strong> we het onderwerp <strong>Algoritm<strong>en</strong></strong>. E<strong>en</strong> algoritme<br />

is, zoals de lezer wellicht bek<strong>en</strong>d is, e<strong>en</strong> methode om e<strong>en</strong> bepaald probleem door e<strong>en</strong> machine te do<strong>en</strong><br />

oploss<strong>en</strong>. Het gaat hier in het bijzonder om problem<strong>en</strong> die op e<strong>en</strong> stap-voor-stap manier kunn<strong>en</strong> word<strong>en</strong><br />

uitgevoerd, waarbij herhaling <strong>van</strong> e<strong>en</strong> aantal ope<strong>en</strong>volg<strong>en</strong>de stapp<strong>en</strong> is toegestaan, maar waarbij toepassing<br />

<strong>van</strong> intellig<strong>en</strong>tie bij het uitvoer<strong>en</strong> <strong>van</strong> de stapp<strong>en</strong> of bij het besliss<strong>en</strong> of e<strong>en</strong> serie stapp<strong>en</strong> herhaald moet<br />

word<strong>en</strong> niet is toegestaan. E<strong>en</strong> algoritme moet e<strong>en</strong> begin <strong>en</strong> e<strong>en</strong> eind hebb<strong>en</strong> <strong>en</strong> de Algoritmiek is de<br />

wet<strong>en</strong>schap die probeert voor soort<strong>en</strong> <strong>van</strong> problem<strong>en</strong> algoritm<strong>en</strong> te mak<strong>en</strong> die zo snel mogelijk <strong>van</strong> dat begin<br />

naar dat eind te kom<strong>en</strong>. Ook in deze tijd, waarin computers steeds sneller lijk<strong>en</strong> te word<strong>en</strong> is het sneller<br />

mak<strong>en</strong> <strong>van</strong> algoritm<strong>en</strong> nog steeds e<strong>en</strong> bedrijvigheid die zinvol is. We zull<strong>en</strong> daar<strong>van</strong> <strong>en</strong>kele overtuig<strong>en</strong>de<br />

voorbeeld<strong>en</strong> voorbij zi<strong>en</strong> kom<strong>en</strong>. Om te kunn<strong>en</strong> bepal<strong>en</strong> of de <strong>en</strong>e algoritme sneller is dan de andere hebb<strong>en</strong> we<br />

wiskundige hulpmiddel<strong>en</strong> nodig die we zull<strong>en</strong> besprek<strong>en</strong> voordat we voorbeeld<strong>en</strong> <strong>van</strong> algoritmische method<strong>en</strong><br />

gaan bekijk<strong>en</strong>. Deze method<strong>en</strong> bestaan uit e<strong>en</strong> aantal truk<strong>en</strong> die in het verled<strong>en</strong> nuttig zijn geblek<strong>en</strong> om<br />

problem<strong>en</strong> <strong>van</strong> e<strong>en</strong> bepaalde soort <strong>van</strong> algoritm<strong>en</strong> te voorzi<strong>en</strong>. We besprek<strong>en</strong> hier achtere<strong>en</strong>volg<strong>en</strong>s de Gulzige<br />

<strong>Algoritm<strong>en</strong></strong>, de Verdeel-<strong>en</strong>-Heersstrategie, <strong>en</strong> het Dynamisch Programmer<strong>en</strong>. Met de ontwerpmethod<strong>en</strong> <strong>en</strong><br />

analytische method<strong>en</strong> in de hand bekijk<strong>en</strong> we verschill<strong>en</strong>de toepassingsgebied<strong>en</strong> <strong>van</strong> de algoritmiek, in het<br />

bijzonder de algoritm<strong>en</strong> op graf<strong>en</strong> <strong>en</strong> de getaltheoretische algoritm<strong>en</strong>. Het laatste onderwerp mondt uit in<br />

de teg<strong>en</strong>woordig in de belangstelling staande public key cryptosystem<strong>en</strong> <strong>en</strong> toepassing<strong>en</strong> daar<strong>van</strong> voor de<br />

beveiliging <strong>van</strong> gegev<strong>en</strong>s.<br />

Het tweede deel wordt door stud<strong>en</strong>t<strong>en</strong> doorgaans als moelijker ervar<strong>en</strong>. We beschouw<strong>en</strong> de problem<strong>en</strong><br />

op zich <strong>en</strong> g<strong>en</strong>eraliser<strong>en</strong> over alle mogelijke algoritm<strong>en</strong> die voor e<strong>en</strong> probleem kunn<strong>en</strong> word<strong>en</strong> bedacht. We<br />

prober<strong>en</strong> hier aan te gev<strong>en</strong> waarom het voor sommige, schijnbaar e<strong>en</strong>voudige, problem<strong>en</strong> schier onmogelijk<br />

lijkt e<strong>en</strong> efficiënte algoritme te bed<strong>en</strong>k<strong>en</strong>, <strong>en</strong> ontwikkel<strong>en</strong> techniek<strong>en</strong> die ons in staat stell<strong>en</strong> zulke problem<strong>en</strong><br />

te herk<strong>en</strong>n<strong>en</strong> <strong>en</strong> te bewijz<strong>en</strong> dat het op z’n minst onwaarschijnlijk is dat efficiënte algoritm<strong>en</strong> voor zo’n<br />

probleem bestaan. De motivatie hiervoor is uiterst praktisch. Aangezi<strong>en</strong> deze problem<strong>en</strong> in allerlei vorm<strong>en</strong><br />

in de praktijk vaak voorkom<strong>en</strong>, is het aannemelijk dat e<strong>en</strong> opdrachtgever e<strong>en</strong> algoritme voor zo’n probleem<br />

7


zou will<strong>en</strong> hebb<strong>en</strong>. Het is waarschijnlijk beter om in dat geval e<strong>en</strong> sterk verhaal te hebb<strong>en</strong> <strong>en</strong> om vooral <strong>van</strong><br />

tevor<strong>en</strong> te kunn<strong>en</strong> besliss<strong>en</strong> dat e<strong>en</strong> efficiënte algoritme voor zo’n probleem niet bestaat. Afhankelijk <strong>van</strong><br />

hoe erg de ondo<strong>en</strong>lijkheid <strong>van</strong> die problem<strong>en</strong> is, kunn<strong>en</strong> ze ondergebracht word<strong>en</strong> in bepaalde klass<strong>en</strong> <strong>en</strong> de<br />

bestudering <strong>van</strong> deze klass<strong>en</strong> is e<strong>en</strong> c<strong>en</strong>traal onderwerp in de complexiteitstheorie. T<strong>en</strong>slotte is er nog het<br />

onderwerp b<strong>en</strong>adering. Als we hebb<strong>en</strong> vastgesteld dat het ge<strong>en</strong> zin heeft voor e<strong>en</strong> probleem e<strong>en</strong> algoritme te<br />

vind<strong>en</strong> die in alle gevall<strong>en</strong> efficiënt is, dan kunn<strong>en</strong> we nog zoek<strong>en</strong> naar algoritm<strong>en</strong> die in de “meeste” gevall<strong>en</strong><br />

effici<strong>en</strong>t zijn. Hierbij kan meeste gevall<strong>en</strong> betek<strong>en</strong><strong>en</strong> dat de algoritme effici<strong>en</strong>t is voor de meeste inputs <strong>van</strong><br />

dezelfde l<strong>en</strong>gte, of dat de meeste pad<strong>en</strong> die e<strong>en</strong> algoritme volgt als onderweg e<strong>en</strong> randomg<strong>en</strong>erator gevolgd<br />

wordt, effici<strong>en</strong>t zijn, dwz. dat de verwachte rek<strong>en</strong>tijd klein is.<br />

De eerste twee del<strong>en</strong> <strong>van</strong> dit boek bevatt<strong>en</strong> e<strong>en</strong> serie onderwerp<strong>en</strong> die in twaalf tot vijfti<strong>en</strong> colleges <strong>van</strong><br />

twee uur gemakkelijk behandeld kunn<strong>en</strong> word<strong>en</strong>, <strong>en</strong> is ongeveer gericht op tweedejaars informaticastud<strong>en</strong>t<strong>en</strong>,<br />

waarbij het deel <strong>Algoritm<strong>en</strong></strong> ongeveer tweederde <strong>van</strong> de tijd in beslag neemt. In geval minder tijd beschikbaar<br />

is, of als bijvoorbeeld de stud<strong>en</strong>t<strong>en</strong> e<strong>en</strong> ruimere wiskundige achtergrond hebb<strong>en</strong> dan hier wordt aang<strong>en</strong>om<strong>en</strong>,<br />

zou bijvoorbeeld de wiskunde-inleiding kunn<strong>en</strong> word<strong>en</strong> overgeslag<strong>en</strong> <strong>en</strong> zou e<strong>en</strong> keuze gemaakt kunn<strong>en</strong> word<strong>en</strong><br />

uit de onderwerp<strong>en</strong> uit het gedeelte <strong>Algoritm<strong>en</strong></strong>. Ook zou e<strong>en</strong> gedeelte <strong>van</strong> het derde deel <strong>van</strong> het boek<br />

behandeld kunn<strong>en</strong> word<strong>en</strong>, waarin onderwerp<strong>en</strong> besprok<strong>en</strong> word<strong>en</strong> die niet noodzakelijk tot basisk<strong>en</strong>nis<br />

algoritmiek gerek<strong>en</strong>d word<strong>en</strong>.<br />

Nag<strong>en</strong>oeg alle stelling<strong>en</strong>, algoritm<strong>en</strong> <strong>en</strong> bewijz<strong>en</strong> kunn<strong>en</strong> wel erg<strong>en</strong>s teruggevond<strong>en</strong> word<strong>en</strong> in de literatuur,<br />

vaak in tekstboek<strong>en</strong>. Slechts wanneer beschikking over de volledige originele tekst—voorzover nog<br />

terug te vind<strong>en</strong>—kan leid<strong>en</strong> tot dieper inzicht of anderszins vermeld<strong>en</strong>swaardig is, heb ik de bron vermeld in<br />

deze tekst. Voor het overige verwijs ik slechts naar de volg<strong>en</strong>de, naar mijn idee lez<strong>en</strong>swaardige, boek<strong>en</strong> <strong>en</strong> de<br />

verwijzing<strong>en</strong> daarin [Har92, JS04, Wil86, Meh85, BB96, Ski98, GT02, GJ79]. In het studiejaar 2007–2008<br />

heb ik deze tekst voor het eerst als syllabus bij het college gebruikt, in plaats <strong>van</strong> e<strong>en</strong> boek. Florian Speelman<br />

<strong>en</strong> Jannis Teuniss<strong>en</strong> hebb<strong>en</strong> uit de eerste tekst e<strong>en</strong> aantal fout<strong>en</strong> gehaald. In het collegejaar 2008-2009 heeft<br />

Koos <strong>van</strong> Stri<strong>en</strong> de tekst nogmaals geheel doorgewerkt, <strong>en</strong> zijn er opnieuw verandering<strong>en</strong> aangebracht. In<br />

2010 heeft Jero<strong>en</strong> Zuiddam e<strong>en</strong> aantal nuttige verbetering<strong>en</strong> gesuggereerd <strong>en</strong> heeft Inge Bethke het college<br />

over snelle Fouriertransformatie gegev<strong>en</strong> <strong>en</strong> uit dat hoofdstuk e<strong>en</strong> aantal fout<strong>en</strong> gehaald.<br />

8


Deel I<br />

<strong>Algoritm<strong>en</strong></strong><br />

9


Het eerste deel <strong>van</strong> de tekst behandelt algoritm<strong>en</strong> <strong>en</strong> hun complexiteit. We besprek<strong>en</strong> de belangrijkste<br />

complexiteitsmat<strong>en</strong> <strong>en</strong> hoe deze mat<strong>en</strong> toe te pass<strong>en</strong> op algoritm<strong>en</strong>. Vervolg<strong>en</strong>s bekijk<strong>en</strong> we e<strong>en</strong> aantal<br />

algoritmische method<strong>en</strong> <strong>en</strong> e<strong>en</strong> aantal voorbeeld<strong>en</strong> <strong>van</strong> hun toepassing<strong>en</strong>. Aparte hoofdstukk<strong>en</strong> vorm<strong>en</strong> de<br />

toepassingsgebied<strong>en</strong> graf<strong>en</strong> <strong>en</strong> numerieke algoritm<strong>en</strong>.<br />

11


Hoofdstuk 1<br />

Voorspel<br />

1.1 Inleiding<br />

Problem<strong>en</strong>, algoritm<strong>en</strong> <strong>en</strong> oplossing<strong>en</strong> vorm<strong>en</strong> e<strong>en</strong> drieë<strong>en</strong>heid in de informatica. Elke vraag die m<strong>en</strong> in één<br />

of andere taal kan stell<strong>en</strong> is e<strong>en</strong> probleem, maar zo’n probleem is voor de informaticus niet noodzakelijk<br />

interessant. E<strong>en</strong> probleem wordt pas interessant voor de informaticus als er sprake is <strong>van</strong> e<strong>en</strong>—doorgaans<br />

oneindige—verzameling <strong>van</strong> soortgelijke vrag<strong>en</strong> die op dezelfde manier naar e<strong>en</strong> oplossing gebracht kunn<strong>en</strong><br />

word<strong>en</strong>. In zo’n geval is deze verzameling <strong>van</strong> problem<strong>en</strong> te <strong>van</strong>g<strong>en</strong> met e<strong>en</strong>zelfde methode, <strong>en</strong> we sprek<strong>en</strong><br />

dan al snel <strong>van</strong> e<strong>en</strong> algoritme om het probleem op te loss<strong>en</strong>.<br />

Naar e<strong>en</strong> formele invulling <strong>van</strong> het begrip algoritme is lang gezocht. <strong>Algoritm<strong>en</strong></strong> om problem<strong>en</strong> op te<br />

loss<strong>en</strong> zijn al zo oud als de wereld. De algoritme die we in paragraaf 4.4 besprek<strong>en</strong> bijvoorbeeld stamt uit<br />

India <strong>en</strong> is zeker 5000 jaar oud. Toch wordt, zeker in Europa, pas zo’n 100 jaar nagedacht over het begrip<br />

algoritme. Als aanleiding voor deze ontwikkeling kunn<strong>en</strong> we de feestrede noem<strong>en</strong> die David Hilbert in het<br />

jaar 1900 in Parijs voor de verzamelde wiskundige gem<strong>en</strong>schap hield noem<strong>en</strong>. In deze rede pres<strong>en</strong>teerde<br />

Hilbert 23 op<strong>en</strong> problem<strong>en</strong> waar<strong>van</strong> hij dacht dat het urg<strong>en</strong>t was dat de wiskundig<strong>en</strong> die in de kom<strong>en</strong>de<br />

eeuw zoud<strong>en</strong> oploss<strong>en</strong>.<br />

E<strong>en</strong> aantal <strong>van</strong> deze problem<strong>en</strong> heeft aanleiding gegev<strong>en</strong> tot revolutionair werk in de wiskunde <strong>en</strong> de<br />

informatica, <strong>en</strong> e<strong>en</strong> aantal heeft natuurlijk ook minder belangstelling 1 gekreg<strong>en</strong>. Van de interessante problem<strong>en</strong><br />

noem<strong>en</strong> we bijvoorbeeld het eerste, <strong>en</strong> volg<strong>en</strong>s Hilbert ook belangrijkste, probleem <strong>van</strong> het bepal<strong>en</strong> <strong>van</strong><br />

het cardinaalgetal <strong>van</strong> het continuum, dat aan G. Cantor werd toegeschrev<strong>en</strong>. Cantor had namelijk bewez<strong>en</strong><br />

dat er meer reële getall<strong>en</strong> dan natuurlijke getall<strong>en</strong> bestaan (zie 6.1) maar de vraag of er misschi<strong>en</strong> e<strong>en</strong><br />

verzameling met meer elem<strong>en</strong>t<strong>en</strong> dan de natuurlijke getall<strong>en</strong>, maar minder elem<strong>en</strong>t<strong>en</strong> dan de reële getall<strong>en</strong><br />

zou kunn<strong>en</strong> bestaan bleef op<strong>en</strong>. De aanname dat er niet zo’n verzameling bestaat werd bek<strong>en</strong>d onder de<br />

naam continuümhypothese Later in die eeuw bleek dat deze vraag onafhankelijk is <strong>van</strong> de axioma’s <strong>van</strong> de<br />

verzameling<strong>en</strong>leer. Gödel bewees in 1938 dat je niet het teg<strong>en</strong>deel kunt bewijz<strong>en</strong>, <strong>en</strong> Coh<strong>en</strong> bewees in 1963<br />

dat je de hypothese zelf niet kunt bewijz<strong>en</strong>. Je kunt deze hypothese dus aannem<strong>en</strong> (of niet) <strong>en</strong> e<strong>en</strong> consist<strong>en</strong>te<br />

verzameling<strong>en</strong>theorie overhoud<strong>en</strong>, ongeveer net als het ev<strong>en</strong>wijdige lijn<strong>en</strong> axioma <strong>van</strong> de Euclidische<br />

meetkunde.<br />

Het tweede probleem dat Hilbert pres<strong>en</strong>teerde was dat <strong>van</strong> de consist<strong>en</strong>tie <strong>van</strong> de axioma’s <strong>van</strong> de rek<strong>en</strong>kunde.<br />

Hilbert, als formalist, geloofde stellig dat de hele wiskunde geautomatiseerd zou kunn<strong>en</strong> word<strong>en</strong><br />

<strong>en</strong> dat elke stelling met behulp <strong>van</strong> mechanische middel<strong>en</strong> geproduceerd zou kunn<strong>en</strong> word<strong>en</strong> door e<strong>en</strong> ijverige<br />

wiskundige (computers war<strong>en</strong> in die tijd onbek<strong>en</strong>d). Deze gedachte dreef onder andere Whitehead <strong>en</strong><br />

1 Als zijn vijfti<strong>en</strong>de probleem pres<strong>en</strong>teerde Hilbert het vind<strong>en</strong> <strong>van</strong> e<strong>en</strong> ” rigorous foundation of Schubert’s <strong>en</strong>umeration calculus”.<br />

Schubert was e<strong>en</strong> neg<strong>en</strong>ti<strong>en</strong>de eeuwse Duitse wiskundige die e<strong>en</strong> veelheid aan constant<strong>en</strong> vond verbond<strong>en</strong> met bepaalde<br />

meetkundige object<strong>en</strong>. Bijvoorbeeld: het aantal lijn<strong>en</strong> dat vier gegev<strong>en</strong> lijn<strong>en</strong> in drie dim<strong>en</strong>sies snijdt is twee, <strong>en</strong> het aantal<br />

kwadratische oppervlakk<strong>en</strong> dat neg<strong>en</strong> kwadratische oppervlakk<strong>en</strong> in de ruimte raakt is 666.841.048. De Nederlandse wiskundige<br />

<strong>van</strong> der Waerd<strong>en</strong> heeft tuss<strong>en</strong> 1920 <strong>en</strong> 1930 hier <strong>en</strong>ig werk aan besteed, als onderdeel <strong>van</strong> het onderzoek in de algebraïsche<br />

meetkunde.<br />

13


Russel tot het producer<strong>en</strong> <strong>van</strong> de ” Principia Mathematica”, e<strong>en</strong> lijvig stuk dat helaas altijd tot vier del<strong>en</strong><br />

beperkt is geblev<strong>en</strong> waarin zo’n formalisering <strong>van</strong> de wiskunde werd ondernom<strong>en</strong>. In 1931 bewees Gödel<br />

de onvolledigheid <strong>van</strong> de rek<strong>en</strong>kunde. Elk eindig consist<strong>en</strong>t stelsel <strong>van</strong> axioma’s voor de rek<strong>en</strong>kunde zal<br />

altijd ware stelling<strong>en</strong> hebb<strong>en</strong> die ge<strong>en</strong> bewijs binn<strong>en</strong> dit stelsel hebb<strong>en</strong>. Dit probleem inspireerde ook het<br />

nad<strong>en</strong>k<strong>en</strong> over wat nu eig<strong>en</strong>lijk zo’n mechanisch rek<strong>en</strong>kundig proces is <strong>en</strong> leidde in de dertiger jar<strong>en</strong> ongeveer<br />

tegelijkertijd tot e<strong>en</strong> aantal formalism<strong>en</strong> voor het begrip berek<strong>en</strong>baarheid. Turing pres<strong>en</strong>teerde in 1936 zijn<br />

Turingmachine [Tur36]. Dit model gebruik<strong>en</strong> we nog steeds om de uitdrukking te gev<strong>en</strong> aan de complexiteit<br />

<strong>van</strong> problem<strong>en</strong> (zie Hoofdstuk 5). Ook omstreeks die tijd pres<strong>en</strong>teerde A. Church zijn lambda calculus—<br />

hoewel de publicatie <strong>van</strong> de lambda caluculus pas rond 1940 geschiedde gaf Church er zeker in 1936 al college<br />

over in Princeton, <strong>en</strong> zijn artikel A note on the Entscheidungsproblem versche<strong>en</strong> in 1936 in het eerste deel<br />

<strong>van</strong> de Journal on Symbolic Logic. Overig<strong>en</strong>s werd<strong>en</strong> beide b<strong>en</strong>adering<strong>en</strong> al in minder toegankelijke tekst<strong>en</strong><br />

rond 1920 door Emil Post neergeschrev<strong>en</strong>, die ook rond die tijd e<strong>en</strong> versie <strong>van</strong> de onvolledigheidsstelling <strong>van</strong><br />

Gödel in e<strong>en</strong> brief aan Church neerschreef. Post was echter niet tevred<strong>en</strong> over dit <strong>en</strong>kele, op zichzelf staande<br />

resultaat, <strong>en</strong> wilde eerst e<strong>en</strong> meer algem<strong>en</strong>e theorie mak<strong>en</strong>.<br />

Wanneer e<strong>en</strong> voorschrift om met e<strong>en</strong> reeks e<strong>en</strong>voudige stapp<strong>en</strong> <strong>van</strong> probleemstelling naar oplossing te<br />

kom<strong>en</strong> in het algeme<strong>en</strong> de naam ” algoritme” kreeg is onbek<strong>en</strong>d. Wel leeft het sterke vermoed<strong>en</strong> dat het woord<br />

afkomstig is <strong>van</strong> het Engelse ” algorism” dat de aanduiding is voor het systeem arithmetische berek<strong>en</strong>ing in<br />

het decimale systeem. Dit woord is weer e<strong>en</strong> verbastering <strong>van</strong> het Latijnse woord Algoritmi dat de latinizering<br />

is <strong>van</strong> de naam <strong>van</strong> Abu Ja’afar Abdullah Muhammad Ibnu Mūsā al-Khawārizmī, auteur <strong>van</strong> het boek Al-<br />

ˇgabr, e<strong>en</strong> verzameling <strong>van</strong> truuks om met het Hindu getall<strong>en</strong>systeem om te gaan, vertaald in het latijn als<br />

Algoritmi de numero Indorum. Al-ˇgabr heeft overig<strong>en</strong>s de weg naar onze taal gevond<strong>en</strong> in de vorm Algebra.<br />

Omdat ” algoritme” oorspronkelijk dus de naam <strong>van</strong> e<strong>en</strong> man is, zull<strong>en</strong> we in deze tekst consequ<strong>en</strong>t sprek<strong>en</strong><br />

<strong>van</strong> ” de algoritme”, in teg<strong>en</strong>stelling tot <strong>van</strong> Dale die het weg<strong>en</strong>s gebrek aan historisch besef heeft over ” het<br />

algoritme”.<br />

Voor problem<strong>en</strong> zijn er algoritm<strong>en</strong> die tot e<strong>en</strong> oplossing leid<strong>en</strong>. Soms zijn dit e<strong>en</strong>voudige algoritm<strong>en</strong><br />

die op de achterkant <strong>van</strong> e<strong>en</strong> sigar<strong>en</strong>doos kunn<strong>en</strong> word<strong>en</strong> uitgevoerd, soms zijn alle computers in de wereld<br />

[CDRH + 96] nodig om de berek<strong>en</strong>ing uit te voer<strong>en</strong>. Soms kunn<strong>en</strong> algoritm<strong>en</strong> binn<strong>en</strong> <strong>en</strong>kele og<strong>en</strong>blikk<strong>en</strong><br />

tot resultaat leid<strong>en</strong>—bijvoorbeeld bij het tracer<strong>en</strong> <strong>van</strong> subatomaire deeltjes. Soms kan e<strong>en</strong> algoritme jar<strong>en</strong><br />

nodig hebb<strong>en</strong> voordat het resultaat bereikt wordt—bijvoorbeeld bij het ontcijfer<strong>en</strong> <strong>van</strong> geheim- of onbek<strong>en</strong>d<br />

[Par99] schrift. Ook is er voor hetzelfde probleem e<strong>en</strong> grote, vaak oneindige verzameling algoritm<strong>en</strong>,<br />

waar<strong>van</strong> de meeste onbek<strong>en</strong>d zijn. Als er e<strong>en</strong> algoritme voor e<strong>en</strong> probleem gevond<strong>en</strong> is, is niet altijd met zekerheid<br />

te zegg<strong>en</strong> of er niet e<strong>en</strong> efficiënte, betere algoritme voor hetzelfde probleem bestaat. De complexiteit<br />

<strong>van</strong> e<strong>en</strong> algoritme kunn<strong>en</strong> we onderzoek<strong>en</strong>. E<strong>en</strong> probleem ontle<strong>en</strong>t zijn complexiteit aan alle algoritm<strong>en</strong> die<br />

voor dat probleem bestaan, <strong>en</strong> dus is de complexiteit <strong>van</strong> e<strong>en</strong> probleem e<strong>en</strong> lastiger onderwerp. We beginn<strong>en</strong><br />

daarom met de complexiteit <strong>van</strong> algoritm<strong>en</strong>.<br />

1.2 Analyse <strong>van</strong> <strong>Algoritm<strong>en</strong></strong><br />

In dit boek zijn we geïnteresseerd in algoritm<strong>en</strong> waarmee problem<strong>en</strong> kunn<strong>en</strong> word<strong>en</strong> opgelost. Als we e<strong>en</strong><br />

algoritme hebb<strong>en</strong> bedacht, dan will<strong>en</strong> we graag wet<strong>en</strong> hoe duur het uitvoer<strong>en</strong> <strong>van</strong> zo’n algoritme is. Hoeveel<br />

tijd <strong>en</strong> geheug<strong>en</strong> kost het uitvoer<strong>en</strong> <strong>van</strong> zo e<strong>en</strong> algoritme. Voordat we daar iets over kunn<strong>en</strong> zegg<strong>en</strong>, moet<strong>en</strong><br />

we eerst afsprek<strong>en</strong> wat e<strong>en</strong> algoritme is, <strong>en</strong> hoe we de kost<strong>en</strong> <strong>van</strong> e<strong>en</strong> algoritme gaan berek<strong>en</strong><strong>en</strong>.<br />

E<strong>en</strong> algoritme is e<strong>en</strong> plan waarmee e<strong>en</strong> computer e<strong>en</strong> probleem kan oploss<strong>en</strong>. Je kunt e<strong>en</strong> algoritme zi<strong>en</strong><br />

als e<strong>en</strong> programma. Het verschil is dat e<strong>en</strong> programma meestal expliciet in één of andere programmeertaal<br />

zegt wat e<strong>en</strong> programma moet do<strong>en</strong>, terwijl e<strong>en</strong> algoritme e<strong>en</strong> veel globalere beschrijving is <strong>van</strong> de stapp<strong>en</strong><br />

die moet<strong>en</strong> word<strong>en</strong> uitgevoerd. In deze tekst beperk<strong>en</strong> we ons wel tot beschrijving<strong>en</strong> die inderdaad gaan over<br />

de stapp<strong>en</strong> die moet<strong>en</strong> word<strong>en</strong> uitgevoerd. Elke algoritme die hier gepres<strong>en</strong>teerd wordt is e<strong>en</strong> recept dat stap<br />

voor stap naar e<strong>en</strong> oplossing <strong>van</strong> het probleem leidt. De algoritm<strong>en</strong> kunn<strong>en</strong> nader gespecificeerd word<strong>en</strong> in<br />

één of andere programmeertaal <strong>en</strong> word<strong>en</strong> dan programma’s, die stap voor stap tot e<strong>en</strong> oplossing leid<strong>en</strong>. Er<br />

zijn in de informatica ook andere manier<strong>en</strong> om teg<strong>en</strong> problem<strong>en</strong> die door computers word<strong>en</strong> opgelost aan te<br />

kijk<strong>en</strong>. Voorbeeld<strong>en</strong> hier<strong>van</strong> zijn, onder toepassing <strong>van</strong> <strong>en</strong>ige simplificatie:<br />

14


Descriptieve programmering. Je geeft de specificatie <strong>van</strong> het probleem <strong>en</strong> het systeem zoekt naar e<strong>en</strong><br />

oplossing. Voorbeeld<strong>en</strong> hier<strong>van</strong> zijn logisch programmer<strong>en</strong> <strong>en</strong> constraint programming.<br />

Functionele programmering. Je geeft de beschrijving <strong>van</strong> het probleem in term<strong>en</strong> <strong>van</strong> functies <strong>en</strong> het<br />

systeem zoekt naar de juiste waard<strong>en</strong>.<br />

Parallel programmer<strong>en</strong>. Er word<strong>en</strong> verschill<strong>en</strong>de algoritm<strong>en</strong> (of dezelfde algoritme meerdere ker<strong>en</strong>)<br />

tegelijkertijd uitgevoerd, al dan niet met onderlinge communicatie.<br />

Quantum computing. Verschill<strong>en</strong>de strom<strong>en</strong> <strong>van</strong> de e<strong>en</strong> algoritme word<strong>en</strong> in superpositie uitgevoerd.<br />

Door interfer<strong>en</strong>tie <strong>en</strong> state collapse wordt de juiste oplossing overgehoud<strong>en</strong>.<br />

Deze alternatieve vorm<strong>en</strong> zull<strong>en</strong> we hier niet besprek<strong>en</strong>. Ons gaat het alle<strong>en</strong> om de klassieke vorm <strong>van</strong> de<br />

algoritme die stap voor stap wordt uitgevoerd, waarbij soms beslissing<strong>en</strong> word<strong>en</strong> g<strong>en</strong>om<strong>en</strong> door het systeem,<br />

maar waarbij het systeem nooit over zo’n beslissing hoeft na te d<strong>en</strong>k<strong>en</strong>. Elke stap kan dus zonder, al dan<br />

niet kunstmatige, intellig<strong>en</strong>tie word<strong>en</strong> uitgevoerd.<br />

1.2.1 Met<strong>en</strong> is wet<strong>en</strong><br />

De e<strong>en</strong>voudigste vorm <strong>van</strong> het onderzoek<strong>en</strong> hoe duur e<strong>en</strong> bepaalde algoritme is, is natuurlijk het gebruik <strong>van</strong><br />

de stopwatch. We schrijv<strong>en</strong> e<strong>en</strong> programma voor het oploss<strong>en</strong> <strong>van</strong> e<strong>en</strong> bepaald probleem voor e<strong>en</strong> bepaalde<br />

computer, <strong>en</strong> drukk<strong>en</strong> vervolg<strong>en</strong>s voor <strong>en</strong> na het uitvoer<strong>en</strong> <strong>van</strong> het programma de stopwatch in <strong>en</strong> kijk<strong>en</strong> dan<br />

hoeveel tijd er is verstrek<strong>en</strong>. De meeste operating systems hebb<strong>en</strong> hier wel e<strong>en</strong> speciale functie voor <strong>en</strong> ook<br />

in de meeste programmeertal<strong>en</strong> kan direct naar de systeemklok word<strong>en</strong> gekek<strong>en</strong>. Om e<strong>en</strong> indruk te krijg<strong>en</strong><br />

<strong>van</strong> de effici<strong>en</strong>tie <strong>van</strong> e<strong>en</strong> algoritme is deze methode zeer bruikbaar. We kunn<strong>en</strong> de gebruikte tijd op e<strong>en</strong><br />

aantal vraagstelling<strong>en</strong>, ook wel instanties <strong>van</strong> e<strong>en</strong> probleem g<strong>en</strong>oemd, met<strong>en</strong> <strong>en</strong> vervolg<strong>en</strong>s uitzett<strong>en</strong> in e<strong>en</strong><br />

grafiek. Door zo’n grafiek door te trekk<strong>en</strong>, kunn<strong>en</strong> we vaak ook voorspelling<strong>en</strong> do<strong>en</strong> over hoe de algoritme<br />

zich zal gedrag<strong>en</strong> op andere, niet geteste instanties. Dat heet extrapolatie.<br />

E<strong>en</strong> voordeel <strong>van</strong> deze methode is dat ze e<strong>en</strong>voudig uit te voer<strong>en</strong> is <strong>en</strong> direct resultaat geeft. E<strong>en</strong> nadeel<br />

is dat je meestal veel instanties moet bekijk<strong>en</strong> om zinnige voorspelling<strong>en</strong> over het gedrag <strong>van</strong> de algoritme<br />

te do<strong>en</strong> <strong>en</strong> dat deze testmethode dus tijdrov<strong>en</strong>d is. E<strong>en</strong> ander nadeel is dat bij geblek<strong>en</strong> ongeschiktheid (de<br />

algoritme is te traag) helemaal niet duidelijk is wat de oorzaak <strong>van</strong> die ongeschiktheid is. Deugt de hele<br />

aanpak niet, of is e<strong>en</strong> bepaald onderdeel <strong>van</strong> het programma veel te lang bezig? T<strong>en</strong>slotte zijn extrapolaties<br />

natuurlijk altijd onzeker.<br />

1.2.2 Voorspell<strong>en</strong> is beter<br />

Als je toch e<strong>en</strong> beschrijving <strong>van</strong> de algoritme hebt voordat je begint, kun je misschi<strong>en</strong> e<strong>en</strong>s kijk<strong>en</strong> of je<br />

<strong>van</strong>tevor<strong>en</strong> e<strong>en</strong> schatting kunt mak<strong>en</strong> <strong>van</strong> het aantal stapp<strong>en</strong> dat die algoritme gaat do<strong>en</strong> om je probleem<br />

op te loss<strong>en</strong>. Als je dan weet hoeveel tijd e<strong>en</strong> <strong>en</strong>kele stap duurt, kun je het aantal stapp<strong>en</strong> gewoon met<br />

de stapduur verm<strong>en</strong>igvuldig<strong>en</strong> om e<strong>en</strong> tijdsduur voor de hele uitvoering te krijg<strong>en</strong>. Lat<strong>en</strong> we dit e<strong>en</strong>s<br />

verduidelijk<strong>en</strong> aan de hand <strong>van</strong> e<strong>en</strong> overbek<strong>en</strong>d voorbeeld.<br />

Stel ik wil het telefoonnumer <strong>van</strong> e<strong>en</strong> vri<strong>en</strong>d opzoek<strong>en</strong> in e<strong>en</strong> telefoonboek. Het telefoonboek bevat<br />

ongeveer 25000 nam<strong>en</strong>, gesorteerd op alfabet. Er zijn verschill<strong>en</strong>de manier<strong>en</strong> om dat te do<strong>en</strong>. Als ik ge<strong>en</strong><br />

ervaring heb met zoek<strong>en</strong>, zal ik mogelijk op bladzijde 1 beginn<strong>en</strong> <strong>en</strong> dan net zolang de bladzijd<strong>en</strong> omslaan<br />

totdat ik de naam <strong>van</strong> mijn vri<strong>en</strong>d gevond<strong>en</strong> heb. Deze methode heet in de algoritmiek linear search <strong>en</strong><br />

wordt door vrijwel niemand voor het opzoek<strong>en</strong> <strong>van</strong> e<strong>en</strong> naam in e<strong>en</strong> telefoonboek gebruikt (waarom?). Toch<br />

zijn er situaties d<strong>en</strong>kbaar waarin linear search de best mogelijke algoritme is.<br />

We zi<strong>en</strong> onmiddelijk dat het aantal nam<strong>en</strong> dat zo de revue passeert zeer afhankelijk is <strong>van</strong> de naam <strong>van</strong><br />

onze vri<strong>en</strong>d. Als deze naam met e<strong>en</strong> A begint, zull<strong>en</strong> we zeer veel minder tijd kwijt zijn dan wanneer deze<br />

naam met e<strong>en</strong> Z begint. Erger nog is het als de naam niet in het boek voorkomt (geheim nummer). We<br />

zull<strong>en</strong> dan alle 25000 nam<strong>en</strong> voorbij zi<strong>en</strong> kom<strong>en</strong> om uiteindelijk gefrustreerd te word<strong>en</strong>. Gemiddeld zull<strong>en</strong><br />

wel erg<strong>en</strong>s in het midd<strong>en</strong> eindig<strong>en</strong>, dwz ongeveer 12000 nam<strong>en</strong> moet<strong>en</strong> onderzoek<strong>en</strong>. Toch is er maar 1<br />

naam waarvoor we precies 12000 nam<strong>en</strong> moet<strong>en</strong> bekijk<strong>en</strong> voordat we hem gevond<strong>en</strong> hebb<strong>en</strong>. De vraag is nu:<br />

15


wat beschouw<strong>en</strong> we als kost<strong>en</strong> <strong>van</strong> ” de algoritme” los <strong>van</strong> de precieze naam die we zoek<strong>en</strong>. De algoritme is<br />

t<strong>en</strong>slotte de methode ” begin bij bladzijde 1 <strong>en</strong> zoek in volgorde totdat je de naam vindt” <strong>en</strong> <strong>van</strong> die algoritme<br />

will<strong>en</strong> we graag de kost<strong>en</strong> wet<strong>en</strong> zonder te hoev<strong>en</strong> zegg<strong>en</strong> om welke naam het precies gaat.<br />

Verschill<strong>en</strong>de Gevall<strong>en</strong> <strong>van</strong> Analyse<br />

Uit het bov<strong>en</strong>staande blijkt al dat er e<strong>en</strong> aantal verschill<strong>en</strong>de antwoord<strong>en</strong> op de vraag ” hoeveel kost de<br />

algoritme” mogelijk is. Drie antwoord<strong>en</strong> word<strong>en</strong> vaak onderscheid<strong>en</strong>: de worst case, de best case <strong>en</strong> de<br />

average case.<br />

We kunn<strong>en</strong> antwoord<strong>en</strong>: ” 25000 stapp<strong>en</strong>”. In het ergste geval lop<strong>en</strong> we de hele lijst door. Dit heet<br />

worst case analyse<br />

We kunn<strong>en</strong> antwoord<strong>en</strong>: ” 1 stap”. In het gunstigste geval vind<strong>en</strong> we de naam onmiddellijk. Dat heet<br />

best case analyse<br />

We kunn<strong>en</strong> antwoord<strong>en</strong>: ” 12500 stapp<strong>en</strong>”. Er zijn net zoveel nam<strong>en</strong> die minder dan 12500 stapp<strong>en</strong><br />

kost<strong>en</strong> als nam<strong>en</strong> die meer kost<strong>en</strong> (aang<strong>en</strong>om<strong>en</strong> dat alle nam<strong>en</strong> in het telefoonboek staan). Dit heet<br />

average case analyse<br />

De best case analyse komt niet zo vaak voor, omdat deze voorspelling niet zoveel waarde heeft. De average<br />

case analyse komt ook niet zo vaak voor omdat deze vorm <strong>van</strong> analyser<strong>en</strong> vaak moelijker is <strong>en</strong> bov<strong>en</strong>di<strong>en</strong> ook<br />

afhankelijk <strong>van</strong> wat voor kansverdeling er voor onze invoer geldt. Nam<strong>en</strong> die beginn<strong>en</strong> met ‘A’ kom<strong>en</strong> in de<br />

praktijk veel vaker voor dan nam<strong>en</strong> die beginn<strong>en</strong> met ‘Q’ <strong>en</strong> het is helemaal niet waar dat alle nam<strong>en</strong> in het<br />

telefoonboek voorkom<strong>en</strong>. We zull<strong>en</strong> ons dus voornamelijk bezighoud<strong>en</strong> met worst case analyse. In de worst<br />

case doet onze aanpak dus net zoveel stapp<strong>en</strong> als er nam<strong>en</strong> in het telefoonboek staan. Als elke vergelijking<br />

0,025 second<strong>en</strong> kost, dan betek<strong>en</strong>t dat dus in dit geval de de algoritme 625 second<strong>en</strong> doet over het vind<strong>en</strong><br />

<strong>van</strong> e<strong>en</strong> willekeurige naam.<br />

Wat is e<strong>en</strong> Stap?<br />

In onze analyse hebb<strong>en</strong> we het over ” 25.000 stapp<strong>en</strong>”, <strong>en</strong> we bedoel<strong>en</strong> met één stap één vergelijking <strong>van</strong> de<br />

gezochte naam met e<strong>en</strong> naam in het telefoonboek. In werkelijkheid gebeurt er natuurlijk veel meer. De file<br />

met nam<strong>en</strong> moet word<strong>en</strong> geop<strong>en</strong>d <strong>en</strong> geslot<strong>en</strong>, de nam<strong>en</strong> word<strong>en</strong> niet in één stap vergelek<strong>en</strong>, maar letter voor<br />

letter, er moet e<strong>en</strong> teller bijgehoud<strong>en</strong> word<strong>en</strong> die zegt of we al aan het einde <strong>van</strong> het telefoonboek zijn gekom<strong>en</strong><br />

<strong>en</strong> nog veel meer. Toch is het zinvol om voor de complexiteit <strong>van</strong> de algoritme te tell<strong>en</strong> hoeveel keer twee<br />

nam<strong>en</strong> met elkaar word<strong>en</strong> vergelek<strong>en</strong> <strong>en</strong> de rest te verwaarloz<strong>en</strong>. Dat komt omdat het vergelijk<strong>en</strong> <strong>van</strong> twee<br />

nam<strong>en</strong> in deze algoritme het vaakst voorkomt. Elke andere operatie komt minder vaak voor. Verder is het<br />

aantal lettervergelijking dat per naamvergelijking wordt uitgevoerd begr<strong>en</strong>sd door de l<strong>en</strong>gte <strong>van</strong> de naam die<br />

we zoek<strong>en</strong>. Als we dus alle operaties bij elkaar zoud<strong>en</strong> optell<strong>en</strong>, dan is er e<strong>en</strong> (constant) getal zodat de totaal<br />

aantal operaties begr<strong>en</strong>sd wordt door dit constante getal keer het aantal naamvergelijking<strong>en</strong>. Verder is elke<br />

individuele operatie te vergelijk<strong>en</strong> met elke andere individuele operatie doordat er e<strong>en</strong> ander constant getal<br />

is dat het verschil in tijd nodig om die operaties uit te voer<strong>en</strong> aangeeft (bijvoorbeeld verm<strong>en</strong>igvuldig<strong>en</strong> <strong>van</strong><br />

twee 8-bits getall<strong>en</strong> kan 10 keer zo duur zijn als het optell<strong>en</strong> <strong>van</strong> twee 8-bits getall<strong>en</strong>). Tot slot verschill<strong>en</strong><br />

computers die we will<strong>en</strong> bekijk<strong>en</strong> nog <strong>van</strong> elkaar doordat elem<strong>en</strong>taire operaties op de <strong>en</strong>e computer e<strong>en</strong><br />

(constant) aantal ker<strong>en</strong> sneller kunn<strong>en</strong> word<strong>en</strong> uitgevoerd. Als we dus will<strong>en</strong> wet<strong>en</strong> hoe lang het zoek<strong>en</strong> in<br />

werkelijke tijd kan gaan dur<strong>en</strong>, dan kunn<strong>en</strong> we aan de hand <strong>van</strong> het aantal naamsvergelijking<strong>en</strong> daarvoor e<strong>en</strong><br />

goede bov<strong>en</strong>gr<strong>en</strong>s krijg<strong>en</strong> door dat aantal met de juiste constant<strong>en</strong> te verm<strong>en</strong>igvuldig<strong>en</strong>. Als we e<strong>en</strong> algoritme<br />

will<strong>en</strong> analyser<strong>en</strong> zoek<strong>en</strong> we dus vaak e<strong>en</strong> operatie die minst<strong>en</strong>s net zo vaak wordt uitgevoerd als alle andere.<br />

Het kan zijn dat dat voor verschill<strong>en</strong>de del<strong>en</strong> <strong>van</strong> de algoritme e<strong>en</strong> andere moet zijn, bijvoorbeeld als we eerst<br />

gaan sorter<strong>en</strong> <strong>en</strong> dan zoek<strong>en</strong>, maar dan tell<strong>en</strong> we de complexiteit <strong>van</strong> de verschill<strong>en</strong>de del<strong>en</strong> <strong>van</strong> de algoritme<br />

gewoon bij elkaar op. Van deze operatie, die in Engelse tekst<strong>en</strong> vaak barometer g<strong>en</strong>oemd wordt, maar die<br />

we hier bij gebrek aan e<strong>en</strong> betere naam voorlopig maar ” spil” zull<strong>en</strong> noem<strong>en</strong>, gev<strong>en</strong> we e<strong>en</strong> (bov<strong>en</strong>)schatting<br />

voor hoe vaak zij wordt uitgevoerd, <strong>en</strong> dat is dan e<strong>en</strong> maat voor de kost<strong>en</strong> <strong>van</strong> de algoritme.<br />

16


Sam<strong>en</strong>gevat zijn de stapp<strong>en</strong> in de analyse <strong>van</strong> e<strong>en</strong> algoritme dus:<br />

• Verdeel de algoritme <strong>en</strong> e<strong>en</strong> aantal sam<strong>en</strong>hang<strong>en</strong>de del<strong>en</strong> (bijvoorbeeld loops).<br />

• Zoek binn<strong>en</strong> elk deel e<strong>en</strong> elem<strong>en</strong>taire operatie die het vaakst wordt uitgevoerd, <strong>en</strong> tel het aantal ker<strong>en</strong><br />

dat die wordt uitgevoerd.<br />

• De (worst-case) complexiteit <strong>van</strong> zo’n deel is e<strong>en</strong> constante maal het aantal ker<strong>en</strong> dat die elem<strong>en</strong>tair<br />

operatie wordt uitgevoerd.<br />

• De (worst-case) complexiteit <strong>van</strong> de algoritme is e<strong>en</strong> constante maal de worst-case complexiteit <strong>van</strong><br />

het duurste onderdeel.<br />

Verderop in de tekst zull<strong>en</strong> we e<strong>en</strong> handige notatie, de O-notatie voor deze complexiteit invoer<strong>en</strong>.<br />

Verschill<strong>en</strong>de <strong>Algoritm<strong>en</strong></strong>, verschill<strong>en</strong>de complexiteit<br />

De analyse <strong>van</strong> algoritm<strong>en</strong> levert e<strong>en</strong> vergelijking tuss<strong>en</strong> verschill<strong>en</strong>de method<strong>en</strong> die we kunn<strong>en</strong> gebruik<strong>en</strong><br />

om voor e<strong>en</strong> probleem de beste algoritme te kiez<strong>en</strong>. In e<strong>en</strong> geval als het bov<strong>en</strong>staande kunn<strong>en</strong> we gebruik<br />

mak<strong>en</strong> <strong>van</strong> het feit dat de lijst nam<strong>en</strong> gesorteerd is, om e<strong>en</strong> aanzi<strong>en</strong>lijk snellere algoritme te krijg<strong>en</strong>. Deze<br />

methode heet binary search <strong>en</strong> gaat als volgt: Vergelijk de naam die je zoekt met de naam die in het midd<strong>en</strong><br />

<strong>van</strong> het boek staat, <strong>en</strong> deel vervolg<strong>en</strong>s het boek in twee del<strong>en</strong>. Als de naam die je zoekt groter is dan de<br />

naam die je teg<strong>en</strong>komt gebruik je vervolg<strong>en</strong>s het tweede deel <strong>en</strong> anders het eerste deel. Dit in tweeën del<strong>en</strong><br />

herhaal je totdat je nog één naam over hebt. Als dat de naam is die je zoekt, dan heb je hem gevond<strong>en</strong> <strong>en</strong><br />

anders staat die naam niet in het boek. Deze methode doet in e<strong>en</strong> telefoonboek <strong>van</strong> 25000 stapp<strong>en</strong> maximaal<br />

slechts 15 stapp<strong>en</strong> (de 2-logaritme <strong>van</strong> 25000, naar bov<strong>en</strong> afgerond) e<strong>en</strong> dramatische verbetering.<br />

Binary search maakt gebruik <strong>van</strong> e<strong>en</strong> eig<strong>en</strong>schap <strong>van</strong> de invoer die het zoek<strong>en</strong> makkelijk maakt, namelijk<br />

dat de invoer alfabetisch gesorteerd is. Deze eig<strong>en</strong>schap is, zeker voor m<strong>en</strong>s<strong>en</strong>, noodzakelijk bij e<strong>en</strong> zo grote<br />

lijst omdat deze anders onhanteerbaar wordt. De eig<strong>en</strong>schap kan echter niet <strong>van</strong> elke lijst voorondersteld<br />

word<strong>en</strong> <strong>en</strong> is ook niet altijd nodig. Als de lijst met nam<strong>en</strong> niet groter dan vijf is bijvoorbeeld lijkt het weinig<br />

zinvol eerst de lijst te gaan sorter<strong>en</strong> om het zoek<strong>en</strong> makkelijker te mak<strong>en</strong>. Lineair zoek<strong>en</strong> in zo’n lijst kost<br />

namelijk vijf vergelijking<strong>en</strong> <strong>en</strong> binair zoek<strong>en</strong> kost maximaal drie vergelijking<strong>en</strong>. Sorter<strong>en</strong> <strong>van</strong> zo’n lijst kan,<br />

afhankelijk <strong>van</strong> de gebruikte sorteeralgoritme, wel 20 vergelijking<strong>en</strong> kost<strong>en</strong>. Wanneer is het gew<strong>en</strong>st de lijst<br />

te sorter<strong>en</strong>?<br />

M<strong>en</strong>gvorm<strong>en</strong> <strong>en</strong> e<strong>en</strong> Nieuwe Analyse<br />

Als we e<strong>en</strong> grote ongesorteerde lijst hebb<strong>en</strong>, dan kan het voordelig zijn de lijst eerst te sorter<strong>en</strong>. E<strong>en</strong> lijst<br />

<strong>van</strong> 25000 nam<strong>en</strong> sorter<strong>en</strong> kan met ongeveer 375000 vergelijking<strong>en</strong> word<strong>en</strong> gedaan. Dat is natuurlijk duur,<br />

maar het voorwerk dat we gedaan hebb<strong>en</strong>, winn<strong>en</strong> we terug omdat elke volg<strong>en</strong>de opzoekactie hoogst<strong>en</strong>s 15<br />

vergelijking<strong>en</strong> kost in plaats <strong>van</strong> de gemiddeld 12500 vergelijking<strong>en</strong> in de ongesorteerde lijst. Na ongeveer<br />

31 keer e<strong>en</strong> naam opzoek<strong>en</strong> hebb<strong>en</strong> we de voorinvestering <strong>van</strong> 375000 vergelijking<strong>en</strong> weer terugverdi<strong>en</strong>d.<br />

Gemiddeld (average case) is het dus voordeliger de lijst eerst te sorter<strong>en</strong> <strong>en</strong> dan de gesorteerde lijst te<br />

gebruik<strong>en</strong>, dan te werk<strong>en</strong> met de ongesorteerde lijst.<br />

Wat als er maar één opzoekactie plaatsvindt? Dan is het onzin om te invester<strong>en</strong> in het sorter<strong>en</strong> <strong>van</strong> de<br />

lijst. Dus analyse <strong>van</strong> het gemiddelde geval is alle<strong>en</strong> zinvol als we zeker wet<strong>en</strong> dat er veel goedkope acties<br />

word<strong>en</strong> uitgevoerd, die teg<strong>en</strong> de dure acties kunn<strong>en</strong> word<strong>en</strong> weggestreept.<br />

Uitgesmeerde kost<strong>en</strong> Er is e<strong>en</strong> methode die dat zeker maakt, namelijk: voer altijd eerst e<strong>en</strong> heel stel<br />

goedkope acties uit voordat e<strong>en</strong> dure actie wordt uitgevoerd. E<strong>en</strong> voorbeeld uit de praktijk hierbij is het<br />

hur<strong>en</strong> <strong>van</strong> ski’s. Het kop<strong>en</strong> <strong>van</strong> ski’s is relatief duur, maar als je ski’s koopt <strong>en</strong> je gaat vaak skiën haal je dat<br />

er op d<strong>en</strong> duur uit. Als je ski’s koopt <strong>en</strong> je gaat niet vaak—omdat je het niet leuk vindt, of omdat er ge<strong>en</strong><br />

sneeuw valt—zijn gekochte ski’s relatief duur. De oplossing voor dit probleem is eerst ski’s te hur<strong>en</strong>, net<br />

zolang totdat je het bedrag hebt uitgegev<strong>en</strong> dat ski’s in de winkel kost<strong>en</strong>. De volg<strong>en</strong>de keer koop je ze. Op<br />

17


deze manier hoef je per skigeleg<strong>en</strong>heid nooit méér dan twee keer de optimale prijs te betal<strong>en</strong>, hoe vaak je ook<br />

gaat. In ons geval zoud<strong>en</strong> we ons kunn<strong>en</strong> voorstell<strong>en</strong> dat de lijst met nam<strong>en</strong> in het telefoonboek niet altijd<br />

heel groot is, maar leeg begint <strong>en</strong> langzaam groeit. E<strong>en</strong> opzoekactie zou dan, zo lang de lijst klein g<strong>en</strong>oeg<br />

is gewoon lineair zoek<strong>en</strong> kunn<strong>en</strong> zijn <strong>en</strong> alle<strong>en</strong> als de lijst onhanteerbaar groot wordt, zoud<strong>en</strong> we kunn<strong>en</strong><br />

besluit<strong>en</strong> eerst de lijst te sorter<strong>en</strong>.<br />

Deze aanpak garandeert ons dat we eerst e<strong>en</strong> heleboel goedkope acties hebb<strong>en</strong> uitgevoerd (lineair zoek<strong>en</strong><br />

in e<strong>en</strong> kleine lijst; nieuwe nam<strong>en</strong> ongesorteerd achter aan de lijst plakk<strong>en</strong>) voordat we e<strong>en</strong> dure operatie<br />

(sorter<strong>en</strong>) uitvoer<strong>en</strong> om nieuwe zoekacties goedkoper te mak<strong>en</strong>. Als we dan e<strong>en</strong> dure gesorteerde lijst hebb<strong>en</strong>,<br />

kunn<strong>en</strong> nieuwe opzoek operaties snel <strong>en</strong> nieuwe invoegoperaties kunn<strong>en</strong> we weer do<strong>en</strong> met e<strong>en</strong> kleine<br />

ongesorteerde lijst, net zo lang tot die lijst weer onhanteerbaar groot wordt. Vervolg<strong>en</strong>s kunn<strong>en</strong> we de twee<br />

lijst<strong>en</strong> weer sam<strong>en</strong>voeg<strong>en</strong> tot e<strong>en</strong> nieuwe, grotere, gesorteerde lijst.<br />

De analyse waarbij we de kost<strong>en</strong> <strong>van</strong> e<strong>en</strong> dure operatie uitsmer<strong>en</strong> over goedkopere eerdere operaties<br />

heet uitgesmeerde-kost<strong>en</strong>analyse (in Engelse tekst<strong>en</strong> amortized case analysis). Ze wordt veel gebruikt als er<br />

datastructur<strong>en</strong> in het spel zijn die het zoek<strong>en</strong> vere<strong>en</strong>voudig<strong>en</strong>. Bijvoorbeeld zoekbom<strong>en</strong> kunn<strong>en</strong> scheefgroei<strong>en</strong><br />

door toevoeg<strong>en</strong> <strong>van</strong> data <strong>en</strong> sommige zoekacties kunn<strong>en</strong> daardoor zeer duur word<strong>en</strong>. E<strong>en</strong> zoekboom kan<br />

gebalanceerd word<strong>en</strong>, maar dat is e<strong>en</strong> dure operatie <strong>en</strong> die moet dus nuttig zijn. We beginn<strong>en</strong> vrijwel altijd<br />

met niets (lege zoekboom) <strong>en</strong> kunn<strong>en</strong> dan goedkope invoegacties <strong>en</strong> zoekacties do<strong>en</strong> net zolang tot de boom<br />

te groot <strong>en</strong> te scheef wordt om zoekacties nog goedkoop te kunn<strong>en</strong> do<strong>en</strong>. De volg<strong>en</strong>de stap is dan het<br />

balancer<strong>en</strong> <strong>van</strong> de boom. Hashtabell<strong>en</strong> word<strong>en</strong> op e<strong>en</strong> bepaalde grootte geïnitialiseerd om e<strong>en</strong> aantal records<br />

te kunn<strong>en</strong> opslaan. Als het aantal records groter wordt dan de tabel, moet deze word<strong>en</strong> uitgebreid, maar<br />

e<strong>en</strong> uitbreiding <strong>van</strong> de tabel met één veld is e<strong>en</strong> dure operatie. Analyse <strong>van</strong> dit geval leert dat het voordelig<br />

is om de tabel, als hij te groot wordt, mete<strong>en</strong> maar twee keer zo groot te mak<strong>en</strong>, <strong>en</strong>, symmetrisch, als er<br />

records verdwijn<strong>en</strong>, de tabel te halver<strong>en</strong> als het aantal records 1/4 <strong>van</strong> het maximaal mogelijke aantal is (de<br />

lezer kan hier gemakkelijk inzi<strong>en</strong> waarom voor 1/4 in plaats <strong>van</strong> voor 1/2 gekoz<strong>en</strong> is).<br />

E<strong>en</strong> ander, misschi<strong>en</strong> niet zo realistisch, maar wel inzichtelijk voorbeeld is dat waarbij we e<strong>en</strong> elem<strong>en</strong>t op<br />

e<strong>en</strong> bepaalde plaats in e<strong>en</strong> stapel will<strong>en</strong> invoeg<strong>en</strong> (waarbij dan de stapel verandert). We moet<strong>en</strong> eerst e<strong>en</strong><br />

aantal elem<strong>en</strong>t<strong>en</strong> <strong>van</strong> bov<strong>en</strong>af de stapel hal<strong>en</strong>, om vervolg<strong>en</strong>s het nieuwe elem<strong>en</strong>t op de rester<strong>en</strong>de stapel te<br />

zett<strong>en</strong>. De verwijderde elem<strong>en</strong>t<strong>en</strong> word<strong>en</strong> niet meer teruggezet. Elke operatie kan ons dwing<strong>en</strong> om de stapel<br />

leeg te mak<strong>en</strong>. E<strong>en</strong> worst-case analyse zou dus zegg<strong>en</strong> dat elke operatie op e<strong>en</strong> stapel <strong>van</strong> grootte n maximaal<br />

n stapp<strong>en</strong> kan kost<strong>en</strong>, maar het afstapel<strong>en</strong> maakt de maximale kost<strong>en</strong> voor volg<strong>en</strong>de afstapeloperaties kleiner!<br />

Elke operatie houdt e<strong>en</strong> aantal ker<strong>en</strong> afstapel<strong>en</strong> <strong>en</strong> e<strong>en</strong> keer opstapel<strong>en</strong> in, maar in e<strong>en</strong> rij <strong>van</strong> n <strong>van</strong> deze<br />

operaties, kan het totaal <strong>van</strong> de afstapeloperaties niet meer dan n zijn, omdat elk elem<strong>en</strong>t maar één keer<br />

afgestapeld kan word<strong>en</strong>, <strong>en</strong> dat geld voor elke n. E<strong>en</strong> totaal <strong>van</strong> n <strong>van</strong> deze operaties, kan zo niet meer<br />

dan 2n stapp<strong>en</strong> kost<strong>en</strong>, dus elke stap kan niet meer dan 2 operaties kost<strong>en</strong>, als we kost<strong>en</strong> dure stapp<strong>en</strong> over<br />

vorige goedkopere stapp<strong>en</strong> mog<strong>en</strong> uitsmer<strong>en</strong>.<br />

De hier gepres<strong>en</strong>teerde analyse (ook wel ” aggregate analysis” g<strong>en</strong>oemd) is e<strong>en</strong> vrij groffe vorm <strong>van</strong> analyser<strong>en</strong>:<br />

tel alle operaties bij elkaar op <strong>en</strong> deel door het aantal operaties. Dat is natuurlijk toegestaan, maar<br />

wijst niet deze vorm <strong>van</strong> uitgesmeerde complexiteit precies aan goedkope <strong>en</strong> dure operaties toe. Hieronder<br />

zull<strong>en</strong> we twee methode <strong>van</strong> analyse besprek<strong>en</strong> die dat wel do<strong>en</strong>, <strong>en</strong> daardoor nauwkeuriger zijn.<br />

E<strong>en</strong> voorbeeld <strong>van</strong> Uitgesmeerde <strong>Complexiteit</strong><br />

We kunn<strong>en</strong> het verschil tuss<strong>en</strong> worst-case analyse <strong>en</strong> amortized-case analyse zi<strong>en</strong> door naar e<strong>en</strong> binaire<br />

teller te kijk<strong>en</strong>. Stel we hebb<strong>en</strong> e<strong>en</strong> binaire teller <strong>van</strong> k plaats<strong>en</strong> <strong>en</strong> we will<strong>en</strong> met deze teller tell<strong>en</strong> tot<br />

2 k . Hoeveel kost dat? Lat<strong>en</strong> we eerst e<strong>en</strong> worst-case analyse do<strong>en</strong>. E<strong>en</strong> teller heeft k bits. Als spil voor<br />

deze algoritme zull<strong>en</strong> we de bitflip gebruik<strong>en</strong>. Als de teller één keer wordt opgehoogd, dan zal dat dus t<strong>en</strong><br />

hoogste k bitflips kost<strong>en</strong>. De teller wordt maximaal 2 k keer opgehoogd, dus de totale kost<strong>en</strong> zull<strong>en</strong> begr<strong>en</strong>sd<br />

blijv<strong>en</strong> door k ×2 k . De worst-case analyse is e<strong>en</strong>voudig, maar geeft ge<strong>en</strong> reëel beeld <strong>van</strong> de werkelijke kost<strong>en</strong>.<br />

Immers niet in elke stap word<strong>en</strong> k bits geflipt. Sterker nog, in de helft <strong>van</strong> de gevall<strong>en</strong> wordt maar één<br />

bit geflipt. In e<strong>en</strong> kwart <strong>van</strong> de gevall<strong>en</strong> word<strong>en</strong> slechts twee bits geflipt <strong>en</strong> in 1/8 <strong>van</strong> de gevall<strong>en</strong> 3 bits.<br />

Als we simpel tell<strong>en</strong> wat het totaal aantal bitflips in alle 2 k gevall<strong>en</strong> is, dan kom<strong>en</strong> we tot de volg<strong>en</strong>de som<br />

2 k<br />

2<br />

× 1 + 2k<br />

4<br />

× 2 + 2k<br />

8<br />

× 3 + . . . + 2k<br />

2 k × k. Dit is e<strong>en</strong> bek<strong>en</strong>de reeks. In Sectie 1.4.3 waarin we onze k<strong>en</strong>nis<br />

18


stap teller kost<strong>en</strong> saldo pot<strong>en</strong>tiaal stap teller kost<strong>en</strong> saldo pot<strong>en</strong>tiaal<br />

1 00001 1 1 1 9 01001 1 2 2<br />

2 00010 2 1 1 10 01010 2 2 2<br />

3 00011 1 2 2 11 01011 1 3 3<br />

4 00100 3 1 1 12 01100 3 1 2<br />

5 00101 1 2 2 13 01101 1 2 3<br />

6 00110 2 2 2 14 01110 2 2 3<br />

7 00111 1 3 3 15 01111 1 4 4<br />

8 01000 4 1 1 16 10000 5 1 1<br />

Figuur 1.1: Uitgesmeerde complexiteit<br />

over het manipuler<strong>en</strong> <strong>van</strong> reeks<strong>en</strong> opfriss<strong>en</strong>, zull<strong>en</strong> we zi<strong>en</strong> dat deze reeks voor elke k begr<strong>en</strong>sd is door 2 × 2 k<br />

<strong>en</strong> dat dus gemiddeld het aantal bitflips dat bij één keer ophog<strong>en</strong> <strong>van</strong> de teller kan word<strong>en</strong> afgeschat met 2<br />

in plaats <strong>van</strong> k flips. Om te bewijz<strong>en</strong> dat ook de uitgesmeerde complexiteit <strong>van</strong> de bitflips begr<strong>en</strong>sd wordt<br />

door 2 moet<strong>en</strong> we aanton<strong>en</strong> dat dat ook het geval is als de teller niet 2 k keer wordt opgehoogd, maar erg<strong>en</strong>s<br />

tuss<strong>en</strong> de 1 <strong>en</strong> de 2 k keer. Hiervoor zijn e<strong>en</strong> tweetal truuks bedacht, de ” bankrek<strong>en</strong>ing” <strong>en</strong> de ” pot<strong>en</strong>tiaal”.<br />

Omdat deze truuks vaak gebruikt word<strong>en</strong>, spreekt m<strong>en</strong> <strong>van</strong> ” method<strong>en</strong>”.<br />

De bankrek<strong>en</strong>ing<br />

E<strong>en</strong> oerhollandse methode om voorbereid te zijn op onverwachte uitgav<strong>en</strong> is spar<strong>en</strong>. Zo kunn<strong>en</strong> we ook<br />

de uitgesmeerde complexiteitsanalyse opvatt<strong>en</strong>. In de Engelse tekst<strong>en</strong> wordt deze analyse aangeduid met<br />

amortized complexity, wat associaties oproept met hypothek<strong>en</strong>. In het geval <strong>van</strong> hypothek<strong>en</strong> vindt echter<br />

altijd eerst e<strong>en</strong> grote l<strong>en</strong>ing plaats, waardoor de spaaranalogie misschi<strong>en</strong> e<strong>en</strong> betere is voor deze vorm <strong>van</strong><br />

analyse. We wet<strong>en</strong> uit de telpartij hierbov<strong>en</strong> dat over e<strong>en</strong> totaal <strong>van</strong> 2 k verhoging<strong>en</strong> <strong>van</strong> de teller niet meer<br />

dan 2 × 2 k bitflips gemaakt word<strong>en</strong> of, gemiddeld, niet meer dan 2 per verhoging. Stel nu dat we voor elke<br />

verhoging 2 operaties in rek<strong>en</strong>ing br<strong>en</strong>g<strong>en</strong> in plaats <strong>van</strong> het werkelijke aantal operaties. Hebb<strong>en</strong> we dan altijd<br />

g<strong>en</strong>oeg ” spaartegoed” om voor alle werkelijk uitgevoerde operaties te betal<strong>en</strong>? Lat<strong>en</strong> we voor e<strong>en</strong> klein geval<br />

e<strong>en</strong>s kijk<strong>en</strong>.<br />

Het lijkt erop dat de bankrek<strong>en</strong>ing altijd voldo<strong>en</strong>de saldo heeft om de tekort<strong>en</strong> te dekk<strong>en</strong> als de twee<br />

operaties die we steeds in rek<strong>en</strong>ing br<strong>en</strong>g<strong>en</strong> niet g<strong>en</strong>oeg zijn. Hoe bewijz<strong>en</strong> we dat? Op dit punt doet de<br />

lezer er goed aan de tekst ev<strong>en</strong> terzijde te legg<strong>en</strong> <strong>en</strong> over deze vraag na te d<strong>en</strong>k<strong>en</strong>.<br />

Kijk naar het verloop <strong>van</strong> het tegoed op de bankrek<strong>en</strong>ing. Telk<strong>en</strong>s valt het tegoed terug naar 1, vlak<br />

nadat e<strong>en</strong> groot aantal bits geflipt zijn. Voor dat mom<strong>en</strong>t loopt het tegoed net g<strong>en</strong>oeg op om voor deze<br />

bitflips te kunn<strong>en</strong> betal<strong>en</strong>. We zi<strong>en</strong> dat tuss<strong>en</strong> de tijd waarin de meest rechtse i bits op 0 staan <strong>en</strong> de tijd<br />

waarop de meest rechtse i bits op 1 staan, het banktegoed precies i groter wordt dan het daarvoor was.<br />

Hier<strong>van</strong> mak<strong>en</strong> we e<strong>en</strong> inductiehypothese: “Als de meest rechtse i bits op 0 staan, dan is het banktegoed<br />

i groter geword<strong>en</strong> vóór dat de meest rechtse i bits op 1 staan.”<br />

Begin met i = 1. Het kost 1 stap om het meest rechtse bit <strong>van</strong> 0 in 1 te verander<strong>en</strong>, <strong>en</strong> er word<strong>en</strong> 2<br />

munt<strong>en</strong> in rek<strong>en</strong>ing gebracht. Het banktegoed groeit dus met 1. Neem vervolg<strong>en</strong>s aan dat de hypothese<br />

waar is voor één of andere i <strong>en</strong> kijk naar e<strong>en</strong> tijdstip t0 waarop de meest rechter i + 1 bits op 0 staan. Eerst<br />

krijg<strong>en</strong> we e<strong>en</strong> tijdstip waarop de meest rechter i bits op 1 staan <strong>en</strong> het i + 1-e bit nog op 0. Weg<strong>en</strong>s onze<br />

aanname is nu het banktegoed i groter dan het was. In de volg<strong>en</strong>de stap word<strong>en</strong> 2 munt<strong>en</strong> op de rek<strong>en</strong>ing<br />

gezet, i munt<strong>en</strong> word<strong>en</strong> gesp<strong>en</strong>deerd om de meest rechtse i bits op 0 te zett<strong>en</strong>, <strong>en</strong> 1 munt om het i + 1e<br />

bit op 1 te zett<strong>en</strong>, waardoor het banktegoed precies 1 groter is dan het op t0 was (2 + i − (i + 1)). Als de<br />

volg<strong>en</strong>de keer de meest rechter i bits op 1 staan (nu dus op i + 1), dan is het banktegoed i + 1 groter dan<br />

het op tijdstip t0 was.<br />

19


De pot<strong>en</strong>tiaalmethode<br />

E<strong>en</strong> nadeel <strong>van</strong> de bankrek<strong>en</strong>ingmethode is dat je <strong>van</strong> tevor<strong>en</strong> e<strong>en</strong> goed idee moet hebb<strong>en</strong> hoeveel je voor e<strong>en</strong><br />

operatie moet spar<strong>en</strong> om hem te kunn<strong>en</strong> uitvoer<strong>en</strong>. E<strong>en</strong> meer dynamische aanpak is de pot<strong>en</strong>tiaalmethode.<br />

Deze is afgeleid <strong>van</strong> de volg<strong>en</strong>de gedachte. Stel ik b<strong>en</strong> e<strong>en</strong> karretje over e<strong>en</strong> weg aan het duw<strong>en</strong>. Elke meter<br />

ik afleg kost me e<strong>en</strong> bepaalde hoeveelheid boterhamm<strong>en</strong> (<strong>en</strong>ergie). Als ik het karretje over e<strong>en</strong> vlakke weg<br />

duw dan kost elke meter mij ev<strong>en</strong>veel <strong>en</strong>ergie. De <strong>en</strong>ige <strong>en</strong>ergie die moet word<strong>en</strong> toegevoegd, is de <strong>en</strong>ergie die<br />

door wrijving warmte wordt. Echter, als ik het karretje e<strong>en</strong> heuvel opduw, dan kost<strong>en</strong> de heuvelop stapp<strong>en</strong><br />

ine<strong>en</strong>s meer <strong>en</strong>ergie, omdat het karretje pot<strong>en</strong>tiaal wint. Al die <strong>en</strong>ergie krijg ik volg<strong>en</strong>s de behoudswett<strong>en</strong><br />

weer terug wanneer het karretje <strong>van</strong> de heuvel afrolt, omdat de zwaartekracht dan helpt duw<strong>en</strong>.<br />

Lat<strong>en</strong> we dit e<strong>en</strong>s vertal<strong>en</strong> naar de kwestie <strong>van</strong> uitgesmeerde complexiteit. Stel ik heb e<strong>en</strong> functie φ(n)<br />

die de pot<strong>en</strong>tiaal <strong>van</strong> de algoritme na de n-de stap voorstelt. Het verschil φ(n) − φ(n − 1) is de verandering<br />

<strong>van</strong> de pot<strong>en</strong>tiaalfunctie tuss<strong>en</strong> stap n − 1 <strong>en</strong> stap n. We nem<strong>en</strong> aan dat φ(0) = 0 <strong>en</strong> dat φ(n) ≥ 0 voor<br />

alle n. Laat t(n) het aantal stapp<strong>en</strong> zijn dat in de n-de stap moet word<strong>en</strong> uitgevoerd <strong>en</strong> definieer ˆt(n) als<br />

t(n)+φ(n)−φ(n−1). Nu geldt voor N stapp<strong>en</strong> �N n=1 ˆt(n) = �N n=1 (t(n)+φ(n)−φ(n−1)) = φ(N)+� N<br />

n=1 t(n)<br />

Dus � ˆt(n) is altijd minst<strong>en</strong>s zo groot als � t(n), dus � ˆt(n) is e<strong>en</strong> bov<strong>en</strong>gr<strong>en</strong>s voor het aantal operaties dat<br />

gedaan wordt voor elke n. Om nu e<strong>en</strong> goede schatting te krijg<strong>en</strong> voor de uitgesmeerde complexiteit <strong>van</strong> het<br />

probleem hoev<strong>en</strong> we slechts e<strong>en</strong> afschatting te mak<strong>en</strong> voor ˆt(n) voor e<strong>en</strong> geschikte functie φ. Net zoals het<br />

bij de bankmethode e<strong>en</strong> probleem was om e<strong>en</strong> geschikte inductiehypothese te vind<strong>en</strong> is het hier natuurlijk<br />

e<strong>en</strong> probleem om e<strong>en</strong> geschikte pot<strong>en</strong>tiaalfunctie te vind<strong>en</strong>. Deze functie moet de eig<strong>en</strong>schap hebb<strong>en</strong> dat<br />

zij aan het begin 0 is, nooit kleiner dan 0 wordt <strong>en</strong> altijd voldo<strong>en</strong>de groot is om de kost<strong>en</strong> op te <strong>van</strong>g<strong>en</strong>.<br />

Ongeveer net zoals wanneer we ’s morg<strong>en</strong>s met weinig <strong>en</strong>ergie, maar met e<strong>en</strong> volle pot koffie op het werk<br />

aankom<strong>en</strong>. We kunn<strong>en</strong> goedkope kopjes koffie uit de pot tapp<strong>en</strong> <strong>en</strong> daarmee <strong>en</strong>ergie opdo<strong>en</strong>. Teg<strong>en</strong> de tijd<br />

dat de pot leeg is, hebb<strong>en</strong> we voldo<strong>en</strong>de <strong>en</strong>ergie verzameld om de dure operatie, het zett<strong>en</strong> <strong>van</strong> e<strong>en</strong> nieuwe<br />

pot, te gaan ondernem<strong>en</strong>.<br />

In het geval <strong>van</strong> de binaire teller kiez<strong>en</strong> we als pot<strong>en</strong>tiaalfunctie het aantal bits in de teller dat op 1 staat<br />

<strong>en</strong> berek<strong>en</strong><strong>en</strong> dan de uitgesmeerde kost<strong>en</strong> <strong>van</strong> e<strong>en</strong> stap, ˆt. Deze pot<strong>en</strong>tiaalfunctie voldoet aan de eis<strong>en</strong>. Zij<br />

begint met 0, wordt onderweg nooit kleiner dan 0, <strong>en</strong> als er e<strong>en</strong> dure operatie nodig is (veel bitflips) dan<br />

staan er ook veel bits op 1. Lat<strong>en</strong> we kijk<strong>en</strong> of deze functie ook precies aan onze behoeft<strong>en</strong> voldoet. Er<br />

zijn 3 gevall<strong>en</strong>: Als er e<strong>en</strong> ev<strong>en</strong> getal in de teller zit, dan wordt het rechterbit geflipt <strong>van</strong> 0 naar 1 <strong>en</strong> de<br />

pot<strong>en</strong>tiaal stijgt met 1, kost<strong>en</strong> 1 + 1 = 2. Als alle bits in de teller 1 zijn, dan word<strong>en</strong> alle k bits geflipt, maar<br />

de pot<strong>en</strong>tiaal valt naar 0, kost<strong>en</strong> k − k = 0. In alle andere gevall<strong>en</strong> word<strong>en</strong> er i bits <strong>van</strong> 1 naar 0 gezet, 1 bit<br />

wordt <strong>van</strong> 0 naar 1 gezet, <strong>en</strong> de pot<strong>en</strong>tiaal daalt met i − 1. De totale kost<strong>en</strong> zijn dan 1 + i − (i − 1) = 2.<br />

1.2.3 Somm<strong>en</strong><br />

1. De bedoeling <strong>van</strong> deze som is oef<strong>en</strong><strong>en</strong> met het met<strong>en</strong> <strong>van</strong> executieduur <strong>van</strong> programma’s waarbij<br />

verschill<strong>en</strong>de algoritm<strong>en</strong> gebruikt word<strong>en</strong>. Zoals we hierbov<strong>en</strong> al gezi<strong>en</strong> hebb<strong>en</strong> zijn er verschill<strong>en</strong>de<br />

manier<strong>en</strong> om teg<strong>en</strong> zoek<strong>en</strong> <strong>en</strong> sorter<strong>en</strong> aan te kijk<strong>en</strong>. We voer<strong>en</strong> het volg<strong>en</strong>de experim<strong>en</strong>t uit. Elke<br />

keer trekk<strong>en</strong> we e<strong>en</strong> random getal tuss<strong>en</strong> de 1 <strong>en</strong> de n, voeg<strong>en</strong> dat getal in, in de structuur die we<br />

gemaakt hebb<strong>en</strong>. Dit do<strong>en</strong> we n keer. Merk op: e<strong>en</strong> getal kan meerdere ker<strong>en</strong> voorkom<strong>en</strong>. Vervolg<strong>en</strong>s<br />

trekk<strong>en</strong> we m keer e<strong>en</strong> willekeurig getal kleiner dan n <strong>en</strong> zoek<strong>en</strong> dat in het array op. De verschill<strong>en</strong>de<br />

gevall<strong>en</strong> zijn de volg<strong>en</strong>de.<br />

(a) E<strong>en</strong> ongeord<strong>en</strong>d array. E<strong>en</strong> nieuw getal wordt steeds achteraan ingevoegd.<br />

(b) E<strong>en</strong> geord<strong>en</strong>d array. Elke keer als e<strong>en</strong> nieuw getal wordt toegevoegd zett<strong>en</strong> we het getal wel<br />

achteraan de rij, maar vervolg<strong>en</strong>s wordt de rij gesorteerd met quicksort.<br />

(c) E<strong>en</strong> geord<strong>en</strong>d array. Elke keer wordt e<strong>en</strong> nieuw getal ingevoegd met insertion sort.<br />

(d) E<strong>en</strong> m<strong>en</strong>gvorm. We houd<strong>en</strong> het array e<strong>en</strong> tijdlang ongeord<strong>en</strong>d, maar als het aantal elem<strong>en</strong>t<strong>en</strong> ” te<br />

groot” wordt, wordt het hele array opnieuw gesorteerd.<br />

Implem<strong>en</strong>teer deze gevall<strong>en</strong> voor verschill<strong>en</strong>de waard<strong>en</strong> <strong>van</strong> n <strong>en</strong> m. Tuss<strong>en</strong> de opdracht<strong>en</strong> door roep<strong>en</strong><br />

we de klok (of time afhankelijk <strong>van</strong> het gebruikte operating system) aan <strong>en</strong> noter<strong>en</strong> de tijd<strong>en</strong> die met de<br />

20


# stapp<strong>en</strong> tijd comm<strong>en</strong>taar<br />

1.000 0.0001 sec<br />

1.000.000 0.001 sec<br />

10.000.000 0.01 sec onzichtbaar<br />

100.000.000 0.1 sec waarneembaar<br />

1.000.000.000 1 sec<br />

10.000.000.000 10 sec<br />

100.000.000.000 100 sec koffie<br />

1.000.000.000.000 16.7 min praatje<br />

10.000.000.000.000 2uuur 47 min GRRR<br />

100.000.000.000.000 27 uur geduld?<br />

1.000.000.000.000.000 11.25 dag<strong>en</strong> opgev<strong>en</strong>?<br />

10.000.000.000.000.000 4 maand<strong>en</strong><br />

100.000.000.000.000.000 3.33 jaar<br />

1.000.000.000.000.000.000. 33 jaar<br />

10.000.000.000.000.000.000 3.3 eeuw<strong>en</strong><br />

Figuur 1.2: Tijd versus aantal stapp<strong>en</strong> op e<strong>en</strong> 1GIPS processor<br />

klokfunctie verkreg<strong>en</strong> word<strong>en</strong>. Maak e<strong>en</strong> tabel. Voor welke n <strong>en</strong> m gaan de verschill<strong>en</strong> tell<strong>en</strong>? Waarom<br />

verwachtte je dat?<br />

1.3 Asymptotische Gr<strong>en</strong>z<strong>en</strong><br />

Vaak zijn we niet zo geïnteresseerd in de kost<strong>en</strong> <strong>van</strong> het zoek<strong>en</strong> <strong>van</strong> e<strong>en</strong> naam in één bepaalde lijst, want als<br />

zo’n zoekactie gemiddeld 12500 stapp<strong>en</strong> kost, wat zegt dat dan over de gebruikte algoritme? We will<strong>en</strong> graag<br />

wet<strong>en</strong> wat zo’n algoritme kost op verschill<strong>en</strong>de instanties <strong>van</strong> het probleem. Dus, wat als we in het algeme<strong>en</strong><br />

e<strong>en</strong> lijst <strong>van</strong> n nam<strong>en</strong> aan de algoritme gev<strong>en</strong> <strong>en</strong> we vrag<strong>en</strong> of e<strong>en</strong> bepaalde naam in die lijst voorkomt. Voor<br />

de twee algoritm<strong>en</strong> uit de vorige sectie kunn<strong>en</strong> we zi<strong>en</strong> dat de eerste zoekmethode ongeveer n stapp<strong>en</strong> kost,<br />

terwijl de tweede zoekmethode ongeveer log n stapp<strong>en</strong> kost. Voor steeds groter word<strong>en</strong>de n zi<strong>en</strong> we dat de<br />

eerste zoekmethode dus e<strong>en</strong> stuk duurder is dan de tweede.<br />

Het is meer informatief te wet<strong>en</strong> hoe e<strong>en</strong> algoritme zich gedraagt op steeds groter word<strong>en</strong>de vrag<strong>en</strong><br />

dan op e<strong>en</strong> <strong>en</strong>kele instantie <strong>van</strong> e<strong>en</strong> probleem. Met andere woord<strong>en</strong>: we will<strong>en</strong> graag zi<strong>en</strong> hoe het aantal<br />

stapp<strong>en</strong> dat e<strong>en</strong> algoritme moet do<strong>en</strong> om e<strong>en</strong> oplossing te vind<strong>en</strong> groeit als functie <strong>van</strong> de grootte <strong>van</strong> de<br />

vraagstelling. Als e<strong>en</strong> algoritme over e<strong>en</strong> twee keer zo grote vraag twee keer zo lang doet, vind<strong>en</strong> we dat in<br />

principe ge<strong>en</strong> probleem. Zoud<strong>en</strong> we het wel e<strong>en</strong> probleem vind<strong>en</strong> als e<strong>en</strong> algoritme over e<strong>en</strong> twee keer zo<br />

grote vraag ti<strong>en</strong> keer zo lang doet? Wat zijn functies die e<strong>en</strong> redelijke verhouding gev<strong>en</strong> tuss<strong>en</strong> de grootte<br />

<strong>van</strong> de vraagstelling—de l<strong>en</strong>gte <strong>van</strong> de invoer—<strong>en</strong> de grootte <strong>van</strong> het probleem? Lat<strong>en</strong> we, als voorbeeld,<br />

e<strong>en</strong>s kijk<strong>en</strong> naar hoeveel tijd er gemoeid is met het do<strong>en</strong> <strong>van</strong> e<strong>en</strong> aantal stapp<strong>en</strong> op e<strong>en</strong> machine die 10 9<br />

bewerking<strong>en</strong> per seconde kan uitvoer<strong>en</strong> (1GIPS). Zie Figuur 1.2.<br />

Als we e<strong>en</strong> machine, al is die nog zo snel, maar voldo<strong>en</strong>de werk gev<strong>en</strong>, wordt de werktijd <strong>van</strong>zelf onacceptabel<br />

lang. E<strong>en</strong> teg<strong>en</strong>werping zou kunn<strong>en</strong> zijn dat in de dagelijkse praktijk e<strong>en</strong> berek<strong>en</strong>ing die 10 20 operaties<br />

kost niet voorkomt. Dit is echter e<strong>en</strong> misvatting die veel met algoritmiek te mak<strong>en</strong> heeft. Lat<strong>en</strong> we e<strong>en</strong>s naar<br />

e<strong>en</strong> voorbeeld kijk<strong>en</strong> waar de keuze <strong>van</strong> de verkeerde algoritme kan leid<strong>en</strong> tot excessief processorgebruik, de<br />

berek<strong>en</strong>ing <strong>van</strong> Fibonacci getall<strong>en</strong>, g<strong>en</strong>oemd naar de Italiaanse wiskundige Leonardo Pisano (1170–1250),<br />

bijg<strong>en</strong>aamd Fibonacci.<br />

In zijn boek ” Liber Abaci” beschrijft Fibonacci e<strong>en</strong> groot aantal problem<strong>en</strong> interessant voor koopmann<strong>en</strong>.<br />

Eén <strong>van</strong> deze problem<strong>en</strong> is het volg<strong>en</strong>de:<br />

E<strong>en</strong> bioloog zet e<strong>en</strong> paar konijn<strong>en</strong> in e<strong>en</strong> afgeslot<strong>en</strong> ruimte. Hoeveel par<strong>en</strong> konijn<strong>en</strong> heeft zij na<br />

e<strong>en</strong> jaar, aang<strong>en</strong>om<strong>en</strong> dat elk paar elke maand e<strong>en</strong> nieuw paar produceert, dat zelf na de tweede<br />

21


n n 2 n 3 2 n 3 n n!<br />

10 10 100 10 3 1024 59049 3628800<br />

20 20 400 8 × 10 3 1.04 × 10 6 3.48 × 10 9 2.43 × 10 18<br />

40 40 1600 6.4 × 10 3 1.1 × 10 12 1.2 × 10 19 8.2 × 10 47<br />

80 80 6400 5.12 × 10 5 1.2 × 10 24 1.4 × 10 38 7 × 10 118<br />

100 100 10 4 10 6 1.2 × 10 30 5.1 × 10 47 9.3 × 10 157<br />

500 500 2.5 × 10 4 1.25 × 10 8 3.2 × 10 150 3.6 × 10 238 1.2 × 10 1134<br />

1000 1000 10 6 10 9 1.7 × 10 301 1.3 × 10 477 4 × 10 2567<br />

maand productief wordt?<br />

Figuur 1.3: Functies <strong>en</strong> aantall<strong>en</strong> operaties<br />

De oplossing is de overbek<strong>en</strong>de Fibonaccireeks of rij <strong>van</strong> Fibonacci 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, . . . (Fibonacci<br />

zocht het twaalfde elem<strong>en</strong>t <strong>van</strong> deze rij). Hier gaat het ons niet om het vind<strong>en</strong> <strong>van</strong> de oplossing, maar om<br />

hoeveel stapp<strong>en</strong> het op e<strong>en</strong> computer kost om de oplossing te vind<strong>en</strong>. E<strong>en</strong> programmeur kan zich er toe lat<strong>en</strong><br />

verleid<strong>en</strong> te observer<strong>en</strong> dat het n-de Fibonaccigetal kan word<strong>en</strong> gevond<strong>en</strong> door de twee vorige bij elkaar op<br />

te tell<strong>en</strong>. Zij schrijft e<strong>en</strong> programma als volgt.<br />

1: F(n)<br />

2: if n = 1 or n = 2 th<strong>en</strong><br />

3: return(1);<br />

4: else<br />

5: return(F (n − 1) + F (n − 2));<br />

6: <strong>en</strong>d if.<br />

Als wij ons afvrag<strong>en</strong> hoeveel rek<strong>en</strong>stapp<strong>en</strong> zo’n programma kost, dan zi<strong>en</strong> we dat we om het 100e getal<br />

uit te rek<strong>en</strong><strong>en</strong> moet<strong>en</strong> wet<strong>en</strong> wat het 99e <strong>en</strong> het 98e getal is, <strong>en</strong> dat we daarvoor moet<strong>en</strong> berek<strong>en</strong><strong>en</strong> wat het<br />

97e <strong>en</strong> het 96e getal is <strong>en</strong>zovoort. In dit programma echter wordt het 98e getal twee keer uitgerek<strong>en</strong>d, zowel<br />

in de berek<strong>en</strong>ing <strong>van</strong> het 100e getal als <strong>van</strong> het 99e getal, <strong>en</strong> beide berek<strong>en</strong>ing<strong>en</strong> roep<strong>en</strong> zelf weer twee andere<br />

berek<strong>en</strong>ing<strong>en</strong> aan. Elke berek<strong>en</strong>ing zal de berek<strong>en</strong>ing <strong>van</strong> twee andere getall<strong>en</strong> vereis<strong>en</strong>, behalve als n = 1 of<br />

n = 2. De berek<strong>en</strong>ing <strong>van</strong> het 100e Fibonacci getal zal met dit programma ongeveer 2 100 stapp<strong>en</strong> kost<strong>en</strong> (we<br />

zull<strong>en</strong> dit verderop nog precies mak<strong>en</strong>), <strong>en</strong> omdat 2 10 ongeveer 10 3 is, zijn dit 10 30 operaties, e<strong>en</strong> aantal dat<br />

ons op pagina 21 nog onrealistisch voorkwam. In het geval <strong>van</strong> de Fibonacci-getall<strong>en</strong> is het niet de aard <strong>van</strong><br />

het probleem dat de oplossing ingewikkeld maakt. Immers, als we onthoud<strong>en</strong> dat het derde fibonacci getal 2<br />

is in plaats <strong>van</strong> dat telk<strong>en</strong>s weer uit te rek<strong>en</strong><strong>en</strong>, hebb<strong>en</strong> we ” slechts” 100 tuss<strong>en</strong>resultat<strong>en</strong> nodig, die elk uit<br />

de twee voorgaande opgeslag<strong>en</strong> tuss<strong>en</strong>resultat<strong>en</strong> kunn<strong>en</strong> word<strong>en</strong> berek<strong>en</strong>d, dus er zijn slechts ongeveer 200<br />

stapp<strong>en</strong> nodig om het 100e Fibonacci-getal te berek<strong>en</strong><strong>en</strong>.<br />

Het verschil tuss<strong>en</strong> de beide bov<strong>en</strong>beschrev<strong>en</strong> algoritm<strong>en</strong> is het verschil tuss<strong>en</strong> e<strong>en</strong> algoritme met expon<strong>en</strong>tiële<br />

(2 n ) looptijd versus e<strong>en</strong> algoritme met lineaire 2 (n) looptijd. Het beantwoord<strong>en</strong> <strong>van</strong> e<strong>en</strong> vraag <strong>van</strong><br />

grootte n kost in het eerste geval 2 n <strong>en</strong> in het tweede geval slechts n stapp<strong>en</strong>. Het verschil in aantal stapp<strong>en</strong><br />

voor verschill<strong>en</strong>de waard<strong>en</strong> <strong>van</strong> n <strong>en</strong> e<strong>en</strong> aantal <strong>van</strong> deze functies wordt in Figuur 1.3 nog e<strong>en</strong>s duidelijk<br />

gemaakt.<br />

We zi<strong>en</strong> aan deze tabel dat voor betrekkelijk kleine vrag<strong>en</strong> (1000 bits is natuurlijk helemaal niet zo groot)<br />

e<strong>en</strong> algoritme die loopt in tijd n! op onze eerdere 1 gigaflops machine onev<strong>en</strong>redig veel tijd in beslag neemt.<br />

Computers word<strong>en</strong> echter steeds sneller <strong>en</strong> het is doorgaans slechts e<strong>en</strong> kwestie <strong>van</strong> e<strong>en</strong> paar maand<strong>en</strong> voordat<br />

er e<strong>en</strong> computer is die twee keer zo snel is. Dit verschijnsel wordt Moore’s law g<strong>en</strong>oemd. Toch zijn er op<br />

verschill<strong>en</strong>de manier<strong>en</strong> gr<strong>en</strong>z<strong>en</strong> aan te gev<strong>en</strong> aan de snelheid die door machines bereikt kunn<strong>en</strong> word<strong>en</strong>. In<br />

de eerste plaats is er de lichtsnelheid, <strong>en</strong> het feit dat om e<strong>en</strong> waarneembaar verschil tuss<strong>en</strong> 0 <strong>en</strong> 1 te hebb<strong>en</strong>,<br />

e<strong>en</strong> electronische schakeling bepaalde minimale afmeting<strong>en</strong> moet hebb<strong>en</strong>. Hieruit kan word<strong>en</strong> afgeleid dat<br />

e<strong>en</strong> machine die e<strong>en</strong> algoritme uitvoert waar de <strong>en</strong>e stap de andere moet opvolg<strong>en</strong> nooit meer dan ongeveer<br />

2 Strikt g<strong>en</strong>om<strong>en</strong> kan de vraag: ” Wat is het n-de Fibonacci getal?” in ongeveer log n bits word<strong>en</strong> gesteld. Het uitvoer<strong>en</strong> <strong>van</strong><br />

n stapp<strong>en</strong> betek<strong>en</strong>t dus in de l<strong>en</strong>gte <strong>van</strong> de invoer nog steeds expon<strong>en</strong>tiële tijd. Meer hierover later.<br />

22


10 35 stapp<strong>en</strong> per seconde zal kunn<strong>en</strong> do<strong>en</strong>. Voor deze machine <strong>en</strong> invoer<strong>en</strong> <strong>van</strong> 1000 bits, toont de tabel aan<br />

dat de tijd die deze machine moet gebruik<strong>en</strong> om e<strong>en</strong> oplossing te vind<strong>en</strong>, voor e<strong>en</strong> algoritme die bijvoorbeeld<br />

n! stapp<strong>en</strong> doet, onacceptabel groot is.<br />

In de tweede plaats is er e<strong>en</strong> veel eerder bereikte gr<strong>en</strong>s, die <strong>van</strong> de <strong>en</strong>ergiedissipatie. Als e<strong>en</strong> machine e<strong>en</strong><br />

oplossing vindt voor de optelling 1 + 1, dan is met het ver<strong>van</strong>g<strong>en</strong> <strong>van</strong> de vergelijking door de oplossing, 2, de<br />

informatie waar deze oplossing <strong>van</strong>daan komt verlor<strong>en</strong>. De berek<strong>en</strong>ing is onomkeerbaar. Dit informatieverlies<br />

of to<strong>en</strong>ame <strong>van</strong> de <strong>en</strong>tropie heeft ontwikkeling <strong>van</strong> warmte tot gevolg. Deze warmte moet erg<strong>en</strong>s naartoe,<br />

<strong>en</strong> wel naar buit<strong>en</strong> door de oppervlakte <strong>van</strong> de chip. E<strong>en</strong> manier om deze <strong>en</strong>ergiedissipatie te verminder<strong>en</strong><br />

is het verlag<strong>en</strong> <strong>van</strong> de voedingsspanning <strong>van</strong> de chip. Hoe lager de voedingsspanning echter, hoe moeilijker<br />

het verschil tuss<strong>en</strong> 0 <strong>en</strong> 1 te zi<strong>en</strong> is <strong>en</strong> dus hoe eerder er fout<strong>en</strong> optred<strong>en</strong>. De huidige voedingsspanning <strong>van</strong><br />

ongeveer 5V lijkt dicht bij de gr<strong>en</strong>s te ligg<strong>en</strong> <strong>van</strong> wat haalbaar is. E<strong>en</strong> teg<strong>en</strong>woordig in de belangstelling<br />

staande aanpak <strong>van</strong> dit probleem is die <strong>van</strong> de omkeerbare berek<strong>en</strong>ing. In plaats <strong>van</strong> tuss<strong>en</strong>resultat<strong>en</strong> weg<br />

te gooi<strong>en</strong> kunn<strong>en</strong> ze ook bewaard blijv<strong>en</strong> zodat <strong>van</strong> de uitvoer terug kan word<strong>en</strong> gerek<strong>en</strong>d naar de invoer.<br />

Deze aanpak blijkt ook in de praktijk aanleiding te gev<strong>en</strong> tot lagere <strong>en</strong>ergiedissipatie.<br />

Hoewel het in de industrie al e<strong>en</strong> tijdje niet meer zo erg hard gaat, vooral <strong>van</strong>wege het <strong>en</strong>ergiedissipatieprobleem<br />

(laptop computers zijn de laatste tijd zelfs weer langzamer geword<strong>en</strong>), heeft het niet veel zin om<br />

bij het afschatt<strong>en</strong> <strong>van</strong> de complexiteit <strong>van</strong> e<strong>en</strong> probleem te kijk<strong>en</strong> naar factor<strong>en</strong> als 2, of in het algeme<strong>en</strong><br />

naar constante factor<strong>en</strong>. Immers, je moet dan altijd precies zegg<strong>en</strong> over welke computer het gaat. Er zijn<br />

nog andere, meer theoretische red<strong>en</strong><strong>en</strong> om constante factor<strong>en</strong> in de berek<strong>en</strong>ing <strong>van</strong> de complexiteit <strong>van</strong> e<strong>en</strong><br />

probleem te verwaarloz<strong>en</strong>. Onder andere is er de ” constant factor speedup” stelling uit de automat<strong>en</strong>theorie<br />

die zegt dat voor e<strong>en</strong> bepaalde algoritme <strong>en</strong> e<strong>en</strong> bepaalde constante altijd e<strong>en</strong> machine te mak<strong>en</strong> is die die<br />

algoritme die constante sneller uitvoert. We gaan hier in deze tekst niet dieper op in. Vaak gaat het in de<br />

algoritmiek erom e<strong>en</strong> constante in de expon<strong>en</strong>t aan versnelling te winn<strong>en</strong>, bijvoorbeeld om e<strong>en</strong> algoritme die<br />

in tijd n 3 loopt te verbeter<strong>en</strong> tot e<strong>en</strong> algoritme die in tijd n 2 loopt. Voor elke constante winst kunn<strong>en</strong> we in<br />

dergelijke gevall<strong>en</strong> natuurlijk n groot g<strong>en</strong>oeg kiez<strong>en</strong> om het effect <strong>van</strong> de constante winst te do<strong>en</strong> verblek<strong>en</strong>.<br />

In het algeme<strong>en</strong> zull<strong>en</strong> we problem<strong>en</strong> waar<strong>van</strong> de rek<strong>en</strong>tijd begr<strong>en</strong>sd wordt door één of ander polynoom<br />

efficiënt oplosbare problem<strong>en</strong> noem<strong>en</strong>. Dit heeft verschill<strong>en</strong>de red<strong>en</strong><strong>en</strong>.<br />

• In de eerste plaats blijkt dat in de praktijk voorkom<strong>en</strong>de problem<strong>en</strong> waarvoor polynomiale algoritm<strong>en</strong><br />

bestaan bijna altijd problem<strong>en</strong> zijn waarvoor algoritm<strong>en</strong> met polynomiale gr<strong>en</strong>z<strong>en</strong> bestaan met e<strong>en</strong><br />

kleine expon<strong>en</strong>t (2,3,4 heel soms 5) <strong>en</strong> deze algoritm<strong>en</strong> (zie tabel 1.3) gedrag<strong>en</strong> zich op redelijke<br />

computers redelijk, dwz vrag<strong>en</strong> <strong>van</strong> niet al te grote om<strong>van</strong>g kost<strong>en</strong> niet al te veel stapp<strong>en</strong>.<br />

• In de tweede plaats hebb<strong>en</strong> polynom<strong>en</strong> de eig<strong>en</strong>schap dat ze zich lat<strong>en</strong> sam<strong>en</strong>stell<strong>en</strong> <strong>en</strong> dat de sam<strong>en</strong>stelling<br />

weer e<strong>en</strong> polynoom is. (Onthoud: e<strong>en</strong> polynoom <strong>van</strong> e<strong>en</strong> polynoom is e<strong>en</strong> polynoom). Dus<br />

hebb<strong>en</strong> we twee bewerking<strong>en</strong> die polynomiale tijd begr<strong>en</strong>sd zijn, dan kunn<strong>en</strong> we, ook omdat in polynomiale<br />

tijd niet meer dan polynomiaal veel bits als uitvoer geg<strong>en</strong>ereerd kunn<strong>en</strong> word<strong>en</strong> die bewerking<strong>en</strong><br />

achter elkaar op de invoer loslat<strong>en</strong>, waarbij het totaal <strong>van</strong> de bewerking<strong>en</strong> toch effici<strong>en</strong>t blijft.<br />

• In de derde plaats groei<strong>en</strong> polynomiaal begr<strong>en</strong>sde algoritm<strong>en</strong> niet al te veel met de groei <strong>van</strong> de<br />

vraagstelling. Dat blijkt al uit de tabel die we hierbov<strong>en</strong> pres<strong>en</strong>teerd<strong>en</strong>, maar ook, als de probleemstelling<br />

met e<strong>en</strong> constante groeit (zeg verdubbelt), dan groeit het polynoom ook met e<strong>en</strong> constante (zie:<br />

(2x) k = 2 k x k ).<br />

• Polynomiale tijd is e<strong>en</strong> ondergr<strong>en</strong>s voor machinemodel onafhankelijk red<strong>en</strong>er<strong>en</strong>. We zull<strong>en</strong> in het<br />

tweede deel zi<strong>en</strong> dat theoretische modell<strong>en</strong> voor machines die <strong>van</strong> praktische voorbeeld<strong>en</strong> zijn afgeleid<br />

elkaar kun<strong>en</strong> simuler<strong>en</strong> in polynomiaal begr<strong>en</strong>sde tijd. Dwz wat de <strong>en</strong>e machine in n stapp<strong>en</strong> kan<br />

uitvoer<strong>en</strong> kan de andere machine in n k stapp<strong>en</strong> uitvoer<strong>en</strong> voor één of andere constante k. Wil je het<br />

dus in je red<strong>en</strong>ering niet over e<strong>en</strong> specifieke machine of specifiek machinemodel hebb<strong>en</strong>, dan zul je alle<br />

polynom<strong>en</strong> als gr<strong>en</strong>z<strong>en</strong> op één hoop moet<strong>en</strong> gooi<strong>en</strong>.<br />

• Je zou kunnn<strong>en</strong> bewer<strong>en</strong> dat lineaire tijd (probleemgrootte n kost n stapp<strong>en</strong>) e<strong>en</strong> ondergr<strong>en</strong>s is voor<br />

e<strong>en</strong> algoritme, omdat elke algoritme t<strong>en</strong>minste deze tijd kwijt is voor het lez<strong>en</strong> <strong>van</strong> de invoer.<br />

23


Dit laatste is niet zo’n heel sterk argum<strong>en</strong>t omdat bijvoorbeeld zoek<strong>en</strong> in e<strong>en</strong> gesorteerde rij niet de gehele<br />

invoer leest, anders zou e<strong>en</strong> log n algoritme niet mogelijk zijn. Ook andere algoritm<strong>en</strong> kunn<strong>en</strong> volstaan met<br />

het slechts gedeeltelijk lez<strong>en</strong> <strong>van</strong> de invoer. We zi<strong>en</strong> echter dat er g<strong>en</strong>oeg argum<strong>en</strong>t<strong>en</strong> bestaan om algoritm<strong>en</strong><br />

waar<strong>van</strong> de looptijd begr<strong>en</strong>sd wordt door e<strong>en</strong> polynoom in de l<strong>en</strong>gte <strong>van</strong> de invoer sam<strong>en</strong> te nem<strong>en</strong> <strong>en</strong> deze<br />

groep de ” efficiënte” algoritm<strong>en</strong> te noem<strong>en</strong>.<br />

1.3.1 Notatie voor de <strong>Complexiteit</strong> <strong>van</strong> <strong>Algoritm<strong>en</strong></strong><br />

Nadat we beargum<strong>en</strong>teerd hebb<strong>en</strong> dat voor de afschatting <strong>van</strong> de complexiteit <strong>van</strong> algoritm<strong>en</strong> constant<strong>en</strong> niet<br />

interessant zijn <strong>en</strong> dat het er bij de afschatting <strong>van</strong> de complexiteit <strong>van</strong> algoritm<strong>en</strong> vooral om gaat hoe deze<br />

algoritm<strong>en</strong> zich gedrag<strong>en</strong> op steeds groter word<strong>en</strong>de invoer<strong>en</strong>, zull<strong>en</strong> we hier e<strong>en</strong> paar symbol<strong>en</strong> invoer<strong>en</strong><br />

waarmee we het gedrag <strong>van</strong> algoritm<strong>en</strong> op invoer<strong>en</strong> <strong>van</strong> l<strong>en</strong>gte n kunn<strong>en</strong> noter<strong>en</strong>. Deze notaties hebb<strong>en</strong><br />

de eig<strong>en</strong>schap dat ze e<strong>en</strong>voudige makkelijk te vergelijk<strong>en</strong> functies gev<strong>en</strong> die e<strong>en</strong> goede afschatting zijn <strong>van</strong><br />

de werkelijke complexiteit (altijd binn<strong>en</strong> e<strong>en</strong> constante factor <strong>van</strong> de werkelijke complexiteit). Bov<strong>en</strong>di<strong>en</strong><br />

lat<strong>en</strong> deze afschatting<strong>en</strong> zich sam<strong>en</strong>stell<strong>en</strong>, dwz als je e<strong>en</strong> stel afschatting<strong>en</strong> hebt voor gedeelt<strong>en</strong> <strong>van</strong> de<br />

algoritme, dan kun je daaruit e<strong>en</strong> afschatting voor de gehele algoritme verkrijg<strong>en</strong>. De afschatting<strong>en</strong> word<strong>en</strong><br />

gedefinieerd als klass<strong>en</strong> <strong>van</strong> functies. De werkelijke complexiteit <strong>van</strong> e<strong>en</strong> algoritme is dus altijd e<strong>en</strong> elem<strong>en</strong>t<br />

<strong>van</strong> de afschatting <strong>van</strong> e<strong>en</strong> functie. Als we bijvoorbeeld kijk<strong>en</strong> naar één <strong>van</strong> de meest gebruikte afschatting<strong>en</strong><br />

O hieronder dan is de goede uitspraak: ” de complexiteit <strong>van</strong> deze algoritme is in O(n)”, g<strong>en</strong>oteerd als<br />

∈ O(n), om e<strong>en</strong> lineaire bov<strong>en</strong>gr<strong>en</strong>s aan te gev<strong>en</strong>, hoewel in veel boek<strong>en</strong> gezegd wordt ” ...is <strong>van</strong> orde n”,<br />

g<strong>en</strong>oteerd als = O(n). Deze taalvervlakking is <strong>van</strong> dezelfde orde als het gebruik <strong>van</strong> ” het” algoritme in plaats<br />

<strong>van</strong> het correcte ” de” algoritme. Helaas is dit niet teg<strong>en</strong> te gaan.<br />

Bov<strong>en</strong>gr<strong>en</strong>z<strong>en</strong><br />

De volg<strong>en</strong>de bov<strong>en</strong>afschatting<strong>en</strong> voor functies zijn in gebruik<br />

O(f) = {g : (∃c, n0 ∈ N)(∀n > n0 ∈ N)[g(n) ≤ cf(n)]} In de klasse O(f) zitt<strong>en</strong> zo alle functies die op<br />

d<strong>en</strong> duur (dat wil zegg<strong>en</strong> voor voldo<strong>en</strong>de grote n kleiner word<strong>en</strong> dan één of andere constante c keer<br />

f(n). Voorbeeld 3n ∈ O(n 2 ) omdat <strong>van</strong>af n = 3 geldt dat 3n ≤ n 2 , maar ook is 3n al kleiner dan of<br />

gelijk aan 3n 2 <strong>van</strong>af n = 1.<br />

o(f) = {g : limn→∞ g(n)<br />

f(n)<br />

= 0}. In o(f) zitt<strong>en</strong> alle functies die echt kleiner word<strong>en</strong> dan f. Vaak zie<br />

je dat g ∈ O(f) <strong>en</strong> g ∈ o(f) sam<strong>en</strong>gaan, maar bijvoorbeeld sin n ∈ O(1) maar niet in o(1), terwijl<br />

bijvoorbeeld wel sin n ∈ O(n).<br />

Ondergr<strong>en</strong>z<strong>en</strong><br />

De volg<strong>en</strong>de onderafschatting<strong>en</strong> voor functies zijn in gebruik<br />

Ω(f) = {g : (∃ɛ > 0, ∃∞ � �<br />

g(ni)<br />

ni) f(ni) > ɛ }. Opmerking<strong>en</strong>:<br />

1. De notatie ∃ ∞ is niet zo heel bek<strong>en</strong>d. Ze betek<strong>en</strong>t “er zijn oneindig veel”<br />

2. Deze definitie maakt <strong>van</strong> Ω de teg<strong>en</strong>hanger <strong>van</strong> o bij ondergr<strong>en</strong>z<strong>en</strong>. In e<strong>en</strong> groot aantal tekst<strong>en</strong><br />

figureert Ω ook als de teg<strong>en</strong>hanger <strong>van</strong> O, <strong>en</strong> is zij gedefineerd als: Ω(f) = {g : (∃c ∈ R + , n0 ∈<br />

N)(∀n > n0 ∈ N)[g(n) ≥ cf(n)]}. Wij zull<strong>en</strong> hier aan de eerste definitie vasthoud<strong>en</strong> om historische<br />

red<strong>en</strong><strong>en</strong>, hoewel het in de praktijk vaak niet zoveel uitmaakt welke <strong>van</strong> de twee definities je<br />

gebruikt. Ook maakt het in de praktijk niet zoveel uit of we nu eis<strong>en</strong> dat c ∈ N of c ∈ R + . In<br />

het laatste geval geldt weliswaar niet dat n2 ∈ Ω n2<br />

2 <strong>en</strong> in het eerste geval wel, maar dergelijke<br />

gevall<strong>en</strong> do<strong>en</strong> zich in de praktijk nauwelijks voor.<br />

ω(f) = {g : limn→∞ f(n)<br />

g(n) = 0}<br />

24


Dubbele gr<strong>en</strong>z<strong>en</strong><br />

Naast bov<strong>en</strong>- <strong>en</strong> ondergr<strong>en</strong>z<strong>en</strong> zijn er ook nog twee notaties voor simultane onder <strong>en</strong> bov<strong>en</strong>gr<strong>en</strong>z<strong>en</strong>.<br />

θ(f) = {g : (∃c1, c2 ∈ R, n0 ∈ N)(∀n > n0 ∈ N)[c1f(n) ≤ g(n) ≤ c2f(n)]}<br />

∼ (f) = {g : limn→∞ g(n)<br />

f(n) = 1}<br />

Al deze notaties hebb<strong>en</strong> de eig<strong>en</strong>schap dat ze simpele betek<strong>en</strong>isvolle gr<strong>en</strong>z<strong>en</strong> kunn<strong>en</strong> gev<strong>en</strong> voor ingewikkelde<br />

algoritm<strong>en</strong>. E<strong>en</strong> algoritme bestaat namelijk vaak uit veel gedeelt<strong>en</strong> die allemaal hun eig<strong>en</strong> complexiteit<br />

hebb<strong>en</strong>. Het programma kan bestaan uit verschill<strong>en</strong>de, vaak g<strong>en</strong>este loops, procedure <strong>en</strong> function calls etc.,<br />

allemaal met eig<strong>en</strong> gr<strong>en</strong>z<strong>en</strong> aan de rek<strong>en</strong>tijd. Deze gr<strong>en</strong>z<strong>en</strong> kunn<strong>en</strong> we apart bepal<strong>en</strong> <strong>en</strong> vervolg<strong>en</strong>s optell<strong>en</strong>.<br />

Het grote voordeel <strong>van</strong> de notatie die we hier hebb<strong>en</strong> afgesprok<strong>en</strong> is dat het optell<strong>en</strong> <strong>van</strong> al die onderdel<strong>en</strong><br />

niet leidt tot e<strong>en</strong> grote, lelijke, onoverzichtelijke uitdrukking. Er geldt bijvoorbeeld de optelregel voor O die<br />

zegt dat O(f(n) + g(n)) = O(max{f(n), g(n)}). Als dus bijvoorbeeld e<strong>en</strong> programma bestaat uit e<strong>en</strong> loop<br />

die O(n 2 ) keer wordt uitgevoerd, gevolgd door e<strong>en</strong> loop <strong>van</strong> complexiteit O(n 3 ), dan is de totale complexiteit<br />

<strong>van</strong> het programma O(n 3 ). Ook zi<strong>en</strong> we hier het grote voordeel <strong>van</strong> het weglat<strong>en</strong> <strong>van</strong> de constant<strong>en</strong>. In<br />

de verschill<strong>en</strong>de loops word<strong>en</strong> e<strong>en</strong> aantal operaties ongeveer ev<strong>en</strong> vaak uitgevoerd. Hebb<strong>en</strong> we bijvoorbeeld<br />

e<strong>en</strong> loop als for i = 1 to n do p = p + 1, dan wordt de variabele p precies n keer verhoogd, maar ook de<br />

variabele i. Toch kunn<strong>en</strong> we de kost<strong>en</strong> <strong>van</strong> deze loop op O(n) operaties stell<strong>en</strong> omdat constante factor<strong>en</strong> bij<br />

de bepaling <strong>van</strong> onze gr<strong>en</strong>z<strong>en</strong> niet meetell<strong>en</strong>. Voor g<strong>en</strong>este for loops kunn<strong>en</strong> we zo de complexiteit bepal<strong>en</strong><br />

door e<strong>en</strong> operatie te vind<strong>en</strong> die in zo’n for loop het vaakst wordt uitgevoerd. In e<strong>en</strong> programmafragm<strong>en</strong>t als:<br />

for i = 1 to n do<br />

if a = b th<strong>en</strong><br />

for j = 1 to m do x = x + 1;<br />

<strong>en</strong>d for<br />

<strong>en</strong>d if<br />

<strong>en</strong>d for<br />

kunn<strong>en</strong> we e<strong>en</strong> aantal operaties onderscheid<strong>en</strong>. De variabele i wordt n keer opgehoogd. De test a = b wordt<br />

n keer uitgevoerd. De variabele j wordt (hoogst<strong>en</strong>s) n × m keer opgehoogd <strong>en</strong> ook de variabele x wordt<br />

hoogst<strong>en</strong>s n × m keer opgehoogd. We zi<strong>en</strong> hier echter dat de optelling x = x + 1 minst<strong>en</strong>s net zo vaak wordt<br />

uitgevoerd als elke andere operatie in deze g<strong>en</strong>este loop <strong>en</strong> daarom kunn<strong>en</strong> we de kost<strong>en</strong> <strong>van</strong> deze loop <strong>van</strong><br />

bov<strong>en</strong> afschatt<strong>en</strong> met e<strong>en</strong> constante keer het aantal ker<strong>en</strong> dat x = x + 1 wordt uitgevoerd. De operatie<br />

x = x + 1 wordt in Engelse tekst<strong>en</strong> vaak barometer g<strong>en</strong>oemd. Dat lijkt in deze tekst minder zinvol, maar<br />

omdat de complexiteit <strong>van</strong> dit stukje programma als het ware hangt aan de operatie x = x+1 zull<strong>en</strong> we deze<br />

operatie hier spil noem<strong>en</strong> (zie ook pagina 16). Als we de complexiteit <strong>van</strong> e<strong>en</strong> loop will<strong>en</strong> bepal<strong>en</strong> gaan we<br />

dus op zoek naar e<strong>en</strong> spil op het diepste niveau <strong>en</strong> bepal<strong>en</strong> hoe vaak deze wordt uitgevoerd. De complexiteit<br />

<strong>van</strong> e<strong>en</strong> nesting <strong>van</strong> loops is vaak het product <strong>van</strong> de complexiteit<strong>en</strong> <strong>van</strong> die loops <strong>en</strong> de complexiteit <strong>van</strong><br />

e<strong>en</strong> stel ope<strong>en</strong>volg<strong>en</strong>de loops kunn<strong>en</strong> we afschatt<strong>en</strong> met de maximale complexiteit <strong>van</strong> die loops.<br />

1.3.2 Somm<strong>en</strong><br />

1. Bed<strong>en</strong>k <strong>en</strong>kele voorbeeld<strong>en</strong> <strong>van</strong> algoritm<strong>en</strong> die niet de gehele invoer hoev<strong>en</strong> te lez<strong>en</strong> voordat ze stopp<strong>en</strong><br />

<strong>en</strong> e<strong>en</strong> antwoord gev<strong>en</strong>.<br />

2. Onderzoek de uitgesmeerde complexiteit <strong>van</strong> zoekbom<strong>en</strong> <strong>en</strong> hashtabell<strong>en</strong>. Waarom halver<strong>en</strong> we de<br />

hashtabel pas wanneer deze voor 1/4e gevuld is <strong>en</strong> niet wanneer deze half gevuld is?<br />

3. Laat zi<strong>en</strong> dat log 3 n ∈ O(n 1/3 ).<br />

4. Geef e<strong>en</strong> voorbeeld <strong>van</strong> e<strong>en</strong> functie f(n) zodat f(n) /∈ O(n) <strong>en</strong> f(n) /∈ Ω(n).<br />

5. E<strong>en</strong> polynoom <strong>van</strong> graad n is e<strong>en</strong> functie a0+a1x+. . .+anx n . Geef e<strong>en</strong> algoritme om de waarde <strong>van</strong> zo’n<br />

polynoom in e<strong>en</strong> gegev<strong>en</strong> punt uit te rek<strong>en</strong><strong>en</strong> <strong>en</strong> bepaal de complexiteit. Bepaal ook de complexiteit<br />

<strong>van</strong> het Horner product, dat is de berek<strong>en</strong>ing p(x) = a0 + x(a1 + x(a2 + x(a3 + . . . + xan)) . . .).<br />

25


6. Conditionele asymptotische notatie. Niet altijd is e<strong>en</strong> asymptotische gr<strong>en</strong>s te gev<strong>en</strong> voor elke waarde<br />

<strong>van</strong> n. Het kan zijn dat e<strong>en</strong> functie bijvoorbeeld O(n 2 ) is alle<strong>en</strong> maar als n e<strong>en</strong> macht <strong>van</strong> 2 is. Voor<br />

bepaalde veel voorkom<strong>en</strong>de functies kunn<strong>en</strong> we zo’n conditionele gr<strong>en</strong>s vertal<strong>en</strong> in e<strong>en</strong> gr<strong>en</strong>s die voor<br />

alle n geldt. We zegg<strong>en</strong> dat e<strong>en</strong> functie f uiteindelijk niet dal<strong>en</strong>d is als er e<strong>en</strong> n0 bestaat zo dat<br />

f(n) ≤ f(n + 1) voor alle n ≥ n0. Verder heet e<strong>en</strong> functie b-glad als f(bn) ∈ O(f(n)), <strong>en</strong> glad als zij<br />

b-glad is voor elke b ≥ 2. Als t uiteindelijk niet dal<strong>en</strong>d is, <strong>en</strong> f is b-glad dan geldt. t(n) ∈ θ{f(n) : n is<br />

e<strong>en</strong> macht <strong>van</strong> b} ⇒ t(n) ∈ θ(f(n)). Bewijs dit.<br />

7. Bewijs dat O(f + g) = O(max{f, g}).<br />

8. De symbol<strong>en</strong> O,o,θ,Ω, <strong>en</strong> ∼ kunn<strong>en</strong> opgevat word<strong>en</strong> als relaties tuss<strong>en</strong> functies (bijvoorbeeld R(f, g) ↔<br />

f ∈ O(g). Welke <strong>van</strong> de aldus gedefiniëerde relaties zijn reflexief (R(f, f)), transitief (R(f, g) ∧<br />

R(g, h) → R(f, h)) <strong>en</strong>/of symmetrisch (R(f, g) ↔ R(g, f))?<br />

9. Geef aan welke relaties f ∈ •(g) geld<strong>en</strong> in onderstaande gevall<strong>en</strong> voor • ∈ {O, o, ∼, θ, Ω}<br />

(a) f(x) = (x 2 + 3x + 1) 3 ; g(x) = x 6 .<br />

(b) f(x) = 2 x ; g(x) = 3 x .<br />

(c) f(x) = x + 4; g(x) = x2 − 3.<br />

(d) f(x) = �<br />

j≤x 1<br />

j2 ; g(x) = 1.<br />

10. Onderzoek de volg<strong>en</strong>de uitsprak<strong>en</strong> op waarheid als f(n) ∈ O(g(n) <strong>en</strong> als f(n) ∈ Ω(g(n)).<br />

(a) f(n) + g(n) ∈ O(g(n)).<br />

(b) f(n) × g(n) ∈ O(g(n).<br />

(c) f(n) − g(n) ∈ O(f(n)).<br />

(d) f(n)<br />

g(n) ∈ θ(f(n)).<br />

1.4 Wiskundige Hulpmiddel<strong>en</strong><br />

Belangrijk bij de Analyse <strong>van</strong> <strong>Algoritm<strong>en</strong></strong> <strong>en</strong> bij het bepal<strong>en</strong> <strong>van</strong> de <strong>Complexiteit</strong> <strong>van</strong> Problem<strong>en</strong> is dat<br />

we kunn<strong>en</strong> tell<strong>en</strong>. In het bijzonder moet<strong>en</strong> we bov<strong>en</strong> <strong>en</strong> ondergr<strong>en</strong>z<strong>en</strong> kunn<strong>en</strong> bepal<strong>en</strong>. Omdat het aantal<br />

operaties, of geheug<strong>en</strong>plaats<strong>en</strong> dat gebruikt wordt vaak als functie <strong>van</strong> de invoer gerepres<strong>en</strong>teerd wordt, <strong>en</strong><br />

dan bov<strong>en</strong>di<strong>en</strong> lang niet altijd in geslot<strong>en</strong> vorm maar veel meer als sam<strong>en</strong>raapsel <strong>van</strong> e<strong>en</strong> aantal telpartij<strong>en</strong><br />

<strong>en</strong> observaties, hebb<strong>en</strong> we wat elem<strong>en</strong>taire wiskunde nodig om e<strong>en</strong> ” schone” afschatting <strong>van</strong> de complexiteit<br />

te krijg<strong>en</strong>. In deze sectie zull<strong>en</strong> we e<strong>en</strong> aantal techniek<strong>en</strong> die hierbij kunn<strong>en</strong> help<strong>en</strong> de revue lat<strong>en</strong> passer<strong>en</strong>.<br />

Dit is mogelijk e<strong>en</strong> herhaling <strong>van</strong> e<strong>en</strong>voudige wiskunde die de lezer al e<strong>en</strong>s eerder heeft gezi<strong>en</strong>. Opfrissing<br />

<strong>van</strong> deze k<strong>en</strong>nis is echter altijd nuttig.<br />

1.4.1 Inductie <strong>en</strong> Recursie<br />

Inductie<br />

Bij e<strong>en</strong> <strong>van</strong> zijn vele bezoek<strong>en</strong> aan <strong>Amsterdam</strong> vertelde Carl Smith e<strong>en</strong>s over zijn ” favorite induction proof”.<br />

Het is e<strong>en</strong> bewijs met inductie dat je nag<strong>en</strong>oeg zonder wiskundige hulpmiddel<strong>en</strong> kunt gev<strong>en</strong> <strong>en</strong> dat door<br />

iedere<strong>en</strong> onmiddellijk begrep<strong>en</strong> wordt. Wellicht heeft de lezer dit probleem al e<strong>en</strong>s eerder gezi<strong>en</strong>. Het gaat<br />

om het vollegg<strong>en</strong> <strong>van</strong> e<strong>en</strong> bord, bestaande uit veld<strong>en</strong>, met stukk<strong>en</strong> <strong>van</strong> de vorm <strong>van</strong> Figuur 1.4.1. Zo’n<br />

L-vormige figuur beslaat precies 3 veld<strong>en</strong> <strong>van</strong> het bord. De bewering is dat voor elk vierkant bestaande uit<br />

2 k × 2 k veld<strong>en</strong> de stukk<strong>en</strong> zo in het vierkant gelegd kunn<strong>en</strong> word<strong>en</strong> dat slechts één veld onbezet blijft, <strong>en</strong><br />

dat veld kan bov<strong>en</strong>di<strong>en</strong> willekeurig <strong>van</strong>tevor<strong>en</strong> word<strong>en</strong> gekoz<strong>en</strong>.<br />

Het inductiebewijs is als volgt. Voor e<strong>en</strong> 2 × 2-vierkant is het simpel. Door rotatie kan elk <strong>van</strong> de vier<br />

veld<strong>en</strong> onbedekt gelat<strong>en</strong> word<strong>en</strong>. Stel dat het probleem kan word<strong>en</strong> opgelost voor k − 1. Bekijk e<strong>en</strong> 2 k × 2 k -<br />

vierkant. Kies e<strong>en</strong> veld dat onbedekt moet blijv<strong>en</strong>. Dit veld ligt in één <strong>van</strong> de vier 2 k−1 × 2 k−1 vierkant<strong>en</strong><br />

26


Figuur 1.4: Met volledige inductie...<br />

die volg<strong>en</strong>s de inductiehypothese kunn<strong>en</strong> word<strong>en</strong> volgelegd. De andere drie word<strong>en</strong> zo volgelegd dat de op<strong>en</strong><br />

veld<strong>en</strong> de drie veld<strong>en</strong> in het midd<strong>en</strong> zijn waar ze alledrie bij elkaar kom<strong>en</strong> <strong>en</strong> op die veld<strong>en</strong> legg<strong>en</strong> we precies<br />

één stuk.<br />

Recursie<br />

E<strong>en</strong> recursieve aanpak <strong>van</strong> programmer<strong>en</strong>, zoals we in Sectie 2.2 zull<strong>en</strong> bekijk<strong>en</strong>, verdeelt e<strong>en</strong> algoritmisch<br />

probleem in kleinere, vaak id<strong>en</strong>tieke stukk<strong>en</strong>. Op deze stukk<strong>en</strong> kan dan weer dezelfde algoritme word<strong>en</strong><br />

gebruikt, net zo lang tot de stukk<strong>en</strong> zo klein geword<strong>en</strong> zijn dat de oplossing triviaal is. Recursieve aanpak<br />

<strong>van</strong> problem<strong>en</strong> <strong>en</strong> inductieve bewijz<strong>en</strong> gaan vaak hand in hand. Hoe zoud<strong>en</strong> we namelijk e<strong>en</strong> oplossing<br />

vind<strong>en</strong> voor het probleem dat hierbov<strong>en</strong> geschetst is? We wet<strong>en</strong> dat het probleem e<strong>en</strong>voudig is voor 2 × 2vierkant<strong>en</strong>,<br />

<strong>en</strong> als we e<strong>en</strong> groter vierkant krijg<strong>en</strong> met daarin e<strong>en</strong> veld, dan kunn<strong>en</strong> we het probleem in vier<br />

kleinere problem<strong>en</strong> opdel<strong>en</strong>, elk met hun eig<strong>en</strong> veld dat vrij gelat<strong>en</strong> moet word<strong>en</strong> om, als we voor deze vier<br />

kleinere problem<strong>en</strong> e<strong>en</strong> oplossing hebb<strong>en</strong> gevond<strong>en</strong>, met toevoeging <strong>van</strong> één stuk e<strong>en</strong> oplossing voor het hele<br />

probleem te g<strong>en</strong>erer<strong>en</strong>.<br />

1.4.2 Recurr<strong>en</strong>te betrekking<strong>en</strong><br />

De methode om e<strong>en</strong> afschatting te krijg<strong>en</strong> voor de complexiteit <strong>van</strong> e<strong>en</strong> probleem waarvoor we e<strong>en</strong> recursieve<br />

algoritme hebb<strong>en</strong> bedacht is het oploss<strong>en</strong> <strong>van</strong> de recurr<strong>en</strong>te betrekking. Stel dat we zoud<strong>en</strong> will<strong>en</strong> wet<strong>en</strong> hoe<br />

moelijk het is de inductieopgave uit 1.4.1 te vind<strong>en</strong>. We zi<strong>en</strong> dat we om e<strong>en</strong> probleem <strong>van</strong> afmeting<strong>en</strong> n op<br />

te loss<strong>en</strong>, we 4 problem<strong>en</strong> <strong>van</strong> afmeting n/2 moet<strong>en</strong> oploss<strong>en</strong>, ofwel T (n) = 4 × T (n/2). Nu kunn<strong>en</strong> we het<br />

volg<strong>en</strong>de zi<strong>en</strong>.<br />

T (n) = 4 × T (n/2)<br />

= 16 × T (n/4)<br />

= 4 3 × T (n/2 3 )<br />

.<br />

.<br />

= 4log n × T (n/2log n )<br />

log n<br />

= 4<br />

= (22 )<br />

log n<br />

= (2 log n ) 2<br />

= n 2<br />

We hebb<strong>en</strong> hier aang<strong>en</strong>om<strong>en</strong> dat de laatste T in deze reeks T (n/2 log n ) = T (1) e<strong>en</strong> triviale waarde (bijvoorbeeld<br />

1) aanneemt. Aangezi<strong>en</strong> de complexiteit voor constante afmeting<strong>en</strong> in ieder geval constant is, <strong>en</strong> we<br />

constant<strong>en</strong> in de O-notatie toch verwaarloz<strong>en</strong> is dit in ons geval ge<strong>en</strong> verkeerde aanname. De recurr<strong>en</strong>te<br />

betrekking laat zich dan als het ware uitroll<strong>en</strong> totdat we e<strong>en</strong> geslot<strong>en</strong> uitdrukking voor de complexiteit <strong>van</strong><br />

het probleem overhoud<strong>en</strong>.<br />

27


Dat is niet altijd het geval. Soms is e<strong>en</strong> recurr<strong>en</strong>te betrekking algem<strong>en</strong>er. In het geval <strong>van</strong> de recursieve<br />

aanpak <strong>van</strong> de Fibonacci-getall<strong>en</strong> zag<strong>en</strong> we dat F (n) = F (n − 1) + F (n − 2). Hier zijn al twee startwaard<strong>en</strong><br />

nodig om <strong>van</strong> de grond te kom<strong>en</strong>. In dit speciale geval hebb<strong>en</strong> we F (0) = F (1) = 1, dus kunn<strong>en</strong> we die<br />

gebruik<strong>en</strong> om F (2), F (3), . . . uit te rek<strong>en</strong><strong>en</strong>. Echter, de vergelijking laat zich dan al niet meer gemakkelijk<br />

uitroll<strong>en</strong>, maar meer uitbom<strong>en</strong>. Van bov<strong>en</strong> naar b<strong>en</strong>ed<strong>en</strong> geeft F (n) steeds twee nieuwe waard<strong>en</strong>, dus<br />

uiteindelijk expon<strong>en</strong>tieel veel waard<strong>en</strong> om uit te rek<strong>en</strong><strong>en</strong>.<br />

E<strong>en</strong> andere e<strong>en</strong>voud bevorder<strong>en</strong>de eig<strong>en</strong>schap aan ons inductievoorbeeld is dat de factor die voor de<br />

T (n/2) staat steeds dezelfde is. Dat kan natuurlijk ook afhankelijk <strong>van</strong> de probleemgrootte zijn. E<strong>en</strong><br />

recurr<strong>en</strong>te betrekking kan bijvoorbeeld <strong>van</strong> de vorm xn+1 = bn+1xn zijn. In dit geval, kunn<strong>en</strong> we de<br />

vergelijking ook uitroll<strong>en</strong> als xn+1 = bn+1xn = bn+1bnxn−1 = . . . = bn+1bnbn−1 · · · b1 × x0. Dat is k<strong>en</strong>nelijk<br />

nog niet moelijk g<strong>en</strong>oeg. Lat<strong>en</strong> we dus e<strong>en</strong> extra moeilijkheid toevoeg<strong>en</strong> <strong>en</strong> kijk<strong>en</strong> naar de vergelijking<br />

xn+1 = bn+1xn + cn+1.<br />

Het uitroll<strong>en</strong> <strong>van</strong> de vergelijking geeft dan achtere<strong>en</strong>volg<strong>en</strong>s<br />

xn+1 = bn+1xn + cn+1<br />

= bn+1(bnxn−1 + cn) + cn+1<br />

= bn+1(bn(bn−1xn−2 + cn−1) + cn) + cn+1.<br />

We rak<strong>en</strong> hierbij al snel het overzicht kwijt.<br />

E<strong>en</strong> betere aanpak voor dit soort vergelijking<strong>en</strong> is de volg<strong>en</strong>de. Eerst definier<strong>en</strong> we e<strong>en</strong> nieuwe variabele yn<br />

door xn = b1b2 · · · bnyn. Vul in b1b2 · · · bn+1yn+1 = bn+1b1b2 · · · bnyn+cn+1. We kunn<strong>en</strong> nu door de coefficiënt<br />

<strong>van</strong> yn del<strong>en</strong> <strong>en</strong> krijg<strong>en</strong> yn+1 = yn + dn+1, waarbij dn+1 = cn+1/(b1 · · · bn+1). Deze vergelijking laat zich<br />

weer uitroll<strong>en</strong> tot de oplossing yn = y0 + �n j=1 dj <strong>en</strong>, door terugsubstitutie xn = (b1 · · · bn)[x0 + �n j=1 dj].<br />

Deze substitutie <strong>van</strong> variabel<strong>en</strong> blijkt e<strong>en</strong> winn<strong>en</strong>de strategie te zijn.<br />

Voorbeeld 1.4.1: Kijk naar de vergelijking xn+1 = 3xn + n, met x0 = 0. Substitueer xn = 3 n yn <strong>en</strong> vind<br />

dat yn+1 = yn + n/3 n+1 ofwel yn = � n−1<br />

j=1 j/3j+1 . Terugsubsitutie <strong>van</strong> yn = x n /3 n geeft<br />

xn = 3 n n−1<br />

×<br />

�<br />

j/3 j+1 .<br />

j=1<br />

Dit is al behoorlijk precies, maar met de techniek<strong>en</strong> uit de sectie 1.4.3 kunn<strong>en</strong> we � n−1<br />

j=1 j/3j+1 nog nauwkeuriger<br />

bepal<strong>en</strong>, zoals verderop blijkt. ✷<br />

Recurr<strong>en</strong>te betrekking<strong>en</strong> als tot nu toe behandeld, noem<strong>en</strong> we eerstegraads recurr<strong>en</strong>te betrekking<strong>en</strong>. Er<br />

is sprake <strong>van</strong> twee variabel<strong>en</strong>, xn <strong>en</strong> xn−1, <strong>en</strong> nog wat andere term<strong>en</strong> die niet <strong>van</strong> de recurr<strong>en</strong>tie afhang<strong>en</strong>.<br />

Deze afhankelijkheid lijkt dus e<strong>en</strong> beetje op de manier waarop de coordinat<strong>en</strong> <strong>van</strong> e<strong>en</strong> eerstegraadsfunctie<br />

(lijn) <strong>van</strong> elkaar afhang<strong>en</strong>. Het is echter ook in de algoritmiek mogelijk dat de afhankelijkheid complexer is.<br />

In de recursieve implem<strong>en</strong>tatie <strong>van</strong> het n-de Fibonacci getal is er afhankelijkheid <strong>van</strong> xn <strong>van</strong> zowel xn−1 als<br />

xn−2 (F (n) = F (n − 1) + F (n − 2)). Ook deze recurr<strong>en</strong>te betrekking kunn<strong>en</strong> we uitroll<strong>en</strong>” totdat alle<strong>en</strong><br />

”<br />

F (0) <strong>en</strong> F (1) nog in de vergelijking staan, maar er is e<strong>en</strong> slimmere manier. Als we e<strong>en</strong> vergelijking hebb<strong>en</strong><br />

als xn = xn−1 + xn−2, dan kunn<strong>en</strong> we e<strong>en</strong>s e<strong>en</strong> oplossing prober<strong>en</strong> <strong>van</strong> de vorm xn = αn voor constante<br />

α. Invull<strong>en</strong> <strong>van</strong> dit probeersel geeft αn = αn−1 + αn−2 of (del<strong>en</strong> door αn−2 ) α2 = α + 1. De kwadratische<br />

vergelijking α2 − α − 1 = 0 laat zich direct oploss<strong>en</strong> <strong>en</strong> geeft α = 1±√5 2 .<br />

In het algeme<strong>en</strong> zijn tweede orde recurr<strong>en</strong>te betrekking<strong>en</strong> <strong>van</strong> de vorm xn = axn−1 + bxn−2 + f(n). Als<br />

de vergelijking α2 = aα + b e<strong>en</strong> oplossing heeft, dan heeft de recurr<strong>en</strong>te betrekking xn = axn−1 + bxn−2 e<strong>en</strong><br />

oplossing in geslot<strong>en</strong> vorm xn = αn , waarbij α één <strong>van</strong> de wortels <strong>van</strong> de vergelijking is. Bij twee gelijke<br />

wortels vind<strong>en</strong> we e<strong>en</strong> oplossing <strong>van</strong> de vorm αn (c1 + c2n) analoog aan de oplossing <strong>van</strong> differ<strong>en</strong>tiaalvergelijking<strong>en</strong>.<br />

Het punt is dat de oplossing<strong>en</strong> <strong>van</strong> deze tweedegraadsvergelijking<strong>en</strong> slechts begr<strong>en</strong>sd lijk<strong>en</strong> te<br />

word<strong>en</strong> door expon<strong>en</strong>tiële functies. Zeker is αn e<strong>en</strong> ondergr<strong>en</strong>s, maar als f(n) ook door αn begr<strong>en</strong>sd wordt,<br />

dan is αn ook e<strong>en</strong> bov<strong>en</strong>gr<strong>en</strong>s voor de groei <strong>van</strong> xn. We vatt<strong>en</strong> dit sam<strong>en</strong> in de volg<strong>en</strong>de stelling.<br />

28


Stelling 1.4.1 Laat {xn}n voldo<strong>en</strong> aan xn ≤ b1xn−1 + . . . + bkxn−k + f(n) met (∀i)[bi ≥ 0], � bi > 1 <strong>en</strong><br />

laat c > 1 zo dat c k = b1c k−1 + . . . + bk. Als f(n) ∈ o(c n ), dan geldt xn ∈ O((c + 1) n ).<br />

Het bewijs <strong>van</strong> deze stelling gaat als volgt. Eerst merk<strong>en</strong> we op dat als t = (c+1) k −b1(c+1) k−1 −. . .−bk,<br />

dan is t > 0. Immers, c k = b1c k−1 + . . . + bk, <strong>en</strong> als e<strong>en</strong> k-de graads functie e<strong>en</strong>maal groter is geword<strong>en</strong> dan<br />

e<strong>en</strong> k − 1-ste graads functie in voor positieve argum<strong>en</strong>t<strong>en</strong>, dan blijft dat zo.<br />

Definieer<br />

K = max{|x0|, |x1|/(c + 1), . . . |xk|/(c + 1) k , max{f(n)/t(c + 1) n−k : n ≥ k}}<br />

Dan is K eindig <strong>en</strong> bov<strong>en</strong>di<strong>en</strong> geldt |xj| ≤ K(c + 1) j voor j ≤ n − 1. We bewer<strong>en</strong> dat |xn| ≤ K(c + 1) n<br />

voor alle n. Stel dat de bewering waar is tot <strong>en</strong> met n − 1, dan<br />

E<strong>en</strong> Master Theorem<br />

|xn| ≤ b1|xn−1| + . . . + bk|xn−k| + f(n)<br />

≤ b1K(c + 1) n−1 + . . . + bkK(c + 1) n−k + f(n)<br />

= K(c + 1) n−k (b1(c + 1) k−1 + . . . + bk) + f(n)<br />

= K(c + 1) n−k ((c + 1) k − t) + f(n)<br />

= K(c + 1) n − (tK(c + 1) n−k − f(n))<br />

≤ K(c + 1) n .<br />

Hoewel goed om te hebb<strong>en</strong>, leert Stelling 1.4.1 ons vooral dat algoritm<strong>en</strong> waar<strong>van</strong> de tijd gegev<strong>en</strong> wordt<br />

door e<strong>en</strong> recurr<strong>en</strong>te betrekking met meerdere term<strong>en</strong> die als index n − c hebb<strong>en</strong>, met c e<strong>en</strong> constante,<br />

ge<strong>en</strong> efficiënte algoritm<strong>en</strong> zijn. In het bereik <strong>van</strong> de efficiënte algoritm<strong>en</strong> kom<strong>en</strong> recurr<strong>en</strong>te betrekking<strong>en</strong> als<br />

T (n) = T (n/2)+f(n) veel vaker voor, zoals we bijvoorbeeld bij zoek<strong>en</strong> <strong>en</strong> sorter<strong>en</strong> verderop zull<strong>en</strong> zi<strong>en</strong>. E<strong>en</strong><br />

recursie als de bov<strong>en</strong>staande kunn<strong>en</strong> we natuurlijk uitroll<strong>en</strong> <strong>en</strong> e<strong>en</strong> geslot<strong>en</strong> uitdrukking voor T (n) in f(n)<br />

krijg<strong>en</strong>, maar er is e<strong>en</strong> meer g<strong>en</strong>erieke aanpak. In e<strong>en</strong> tekstboek als bijvoorbeeld dat <strong>van</strong> Corm<strong>en</strong>, Leiserson<br />

<strong>en</strong> Rivest [CLR90] wordt deze aanpak ” The Master Theorem” g<strong>en</strong>oemd. Op veel andere plaats<strong>en</strong> wordt<br />

deze aanpak de Akra-Bazzi methode g<strong>en</strong>oemd, naar de auteurs <strong>van</strong> [AB98]. Beide method<strong>en</strong> hebb<strong>en</strong> veel<br />

geme<strong>en</strong>, al dekt de Akra-Bazzi methode meer gevall<strong>en</strong>. Het gaat om recurr<strong>en</strong>te betrekking<strong>en</strong> <strong>van</strong> de vorm<br />

un =<br />

k�<br />

i=1<br />

aiu ⌊ n<br />

b i ⌋ + g(n).<br />

De wiskundig geïnteresseerde lezer wordt aangemoedigd om het artikel [AB98] te lez<strong>en</strong>, maar voor de<br />

analyse <strong>van</strong> algoritm<strong>en</strong> kan vaak word<strong>en</strong> volstaan met e<strong>en</strong> sterk vere<strong>en</strong>voudigde aanpak zoals in [CLR90].<br />

Vaak is er in e<strong>en</strong> recurr<strong>en</strong>te betrekking die uit e<strong>en</strong> complexiteitsanalyse volgt namelijk slechts sprake <strong>van</strong><br />

één <strong>en</strong>kele veranderlijke, d.w.z. de recurr<strong>en</strong>te betrekking is <strong>van</strong> de vorm.<br />

�<br />

T (n) =<br />

We kunn<strong>en</strong> dan volstaan met de vere<strong>en</strong>voudiging:<br />

1. Als f(n) ∈ O(n log b a−ɛ ) dan T (n) ∈ θ(n log b a ).<br />

c als n < d<br />

aT (n/b) + f(n) als n ≥ d<br />

2. Als f(n) ∈ θ(n log b a log k n) dan T (n) ∈ θ(n log b a log k+1 n)<br />

3. Als f(n) ∈ Ω(n log b a+ɛ ) <strong>en</strong> (∃δ < 1)[af(n/b) ≤ δf(n)] dan T (n) ∈ θ(f(n)).<br />

Deze vere<strong>en</strong>voudiging <strong>van</strong> de stelling is bij veel complexiteitsanalyse <strong>van</strong> algoritm<strong>en</strong> e<strong>en</strong> machtig wap<strong>en</strong>.<br />

Voorbeeld 1.4.2:<br />

29


1. Bij de algoritme voor mergesort, wordt e<strong>en</strong> array verdeeld in twee arrays <strong>van</strong> de halve grootte, die<br />

vervolg<strong>en</strong>s gesorteerd word<strong>en</strong> <strong>en</strong> weer sam<strong>en</strong>gevoegd tot e<strong>en</strong> gesorteerd array <strong>van</strong> de oorspronkelijke<br />

grootte. Dat sam<strong>en</strong>voeg<strong>en</strong> kost tijd proportioneel aan de l<strong>en</strong>gte <strong>van</strong> het array. De recurr<strong>en</strong>te betrekking<br />

die daarbij hoort is<br />

T (n) = 2T (n/2) + O(n).<br />

Met bov<strong>en</strong>staande stelling zi<strong>en</strong> we dat a = b = 2 dus n log b a = n, dus f(n) ∈ O(n log b a ), maar<br />

f(n) �∈ O(n log b a−ɛ ), ofwel we zitt<strong>en</strong> in geval 2 met k = 0. Gevolg: T (n) ∈ θ(n log n).<br />

2. Gewone matrixoptelling kunn<strong>en</strong> we recursief do<strong>en</strong> door vier matrices <strong>van</strong> de halve grootte bij elkaar<br />

op te tell<strong>en</strong>. De recurr<strong>en</strong>te betrekking die daarbij hoort is<br />

T (n) = 4T (n/2) + O(1).<br />

We zitt<strong>en</strong> hiermee in geval 1 <strong>van</strong> de stelling, <strong>en</strong> dus T (n) ∈ θ(n 2 ), want log 2 4 = 2.<br />

3. Gewone matrixverm<strong>en</strong>igvuldiging kan gebeur<strong>en</strong> door 8 matrices <strong>van</strong> de halve grootte met elkaar te<br />

verm<strong>en</strong>igvuldig<strong>en</strong>, <strong>en</strong> dan de resultat<strong>en</strong> <strong>van</strong> de verm<strong>en</strong>igvuldiging twee aan twee bij elkaar op te tell<strong>en</strong>.<br />

Dat zijn vier optelling<strong>en</strong>. We hebb<strong>en</strong> gezi<strong>en</strong> dat matrixoptelling θ(n 2 ) bewerking<strong>en</strong> kost, dus is de<br />

recurr<strong>en</strong>te betrekking die hierbij hoort<br />

T (n) = 8T (n/2) + O(n 2 ).<br />

We zi<strong>en</strong> hier a = 8, b = 2, dus logba = 3, <strong>en</strong> n 2 ∈ O(n 3 ) dus T (n) ∈ θ(n 3 ).<br />

4. Stel we hebb<strong>en</strong> e<strong>en</strong> rij <strong>van</strong> n getall<strong>en</strong> waaruit we e<strong>en</strong> deel <strong>van</strong> log n getall<strong>en</strong> will<strong>en</strong> selecter<strong>en</strong> die <strong>van</strong><br />

klein naar groot gesorteerd is. Dat kunn<strong>en</strong> we do<strong>en</strong> door bijvoorbeeld log n keer het minimum <strong>van</strong> de<br />

rij te nem<strong>en</strong>, maar aangezi<strong>en</strong> het vind<strong>en</strong> <strong>van</strong> het minimum <strong>van</strong> e<strong>en</strong> rij O(n) stapp<strong>en</strong> kost, zijn we dan<br />

n+n−1+n−2+. . .+n−log n stapp<strong>en</strong> bezig <strong>en</strong> dat is θ(n log n). Omdat we niet zoveel getall<strong>en</strong> nodig<br />

hebb<strong>en</strong>, kunn<strong>en</strong> we ook als we het minimum <strong>van</strong> e<strong>en</strong> rij hebb<strong>en</strong> gevond<strong>en</strong>, vervolg<strong>en</strong>s het minimum<br />

zoek<strong>en</strong> <strong>van</strong> de helft <strong>van</strong> de overgeblev<strong>en</strong> rij. Dan zijn de kost<strong>en</strong><br />

T (n) = n + T (n/2).<br />

Volg<strong>en</strong>s bov<strong>en</strong>staande stelling is dan a = 1, b = 2 → log b a = 0, dus kom<strong>en</strong> we in geval 3, waaruit volgt<br />

dat T (n) ∈ θ(n).<br />

1.4.3 Reeks<strong>en</strong><br />

Het optell<strong>en</strong> <strong>van</strong> complexiteit <strong>van</strong> verschill<strong>en</strong>de stukjes <strong>van</strong> e<strong>en</strong> programma is e<strong>en</strong> belangrijk onderdeel <strong>van</strong> de<br />

bepaling <strong>van</strong> de complexiteit <strong>van</strong> problem<strong>en</strong>. Echter, de optelling is vaak afhankelijk <strong>van</strong> e<strong>en</strong> variabele. De<br />

tweede keer dat e<strong>en</strong> stukje programma wordt uitgevoerd is vaak de complexiteit <strong>van</strong> dat stukje programma<br />

anders. E<strong>en</strong> voorbeeld is het sam<strong>en</strong>stell<strong>en</strong> <strong>van</strong> twee gesorteerde rij<strong>en</strong> tot e<strong>en</strong> nieuwe gesorteerde rij in de<br />

algoritme mergesort(zie 2.2). Deze algoritme laat zich uitlegg<strong>en</strong> als volgt. E<strong>en</strong> rij die bestaat uit één getal<br />

is altijd gesorteerd. Verder kunn<strong>en</strong> we twee gesorteerde rij<strong>en</strong> <strong>van</strong> l<strong>en</strong>gte n sam<strong>en</strong>stell<strong>en</strong> tot e<strong>en</strong> gesorteerde<br />

rij <strong>van</strong> l<strong>en</strong>gte 2n door de twee eerste elem<strong>en</strong>t<strong>en</strong> met elkaar te vergelijk<strong>en</strong> <strong>en</strong> daar<strong>van</strong> de kleinste weg te<br />

schrijv<strong>en</strong>, net zo lang tot de beide rij<strong>en</strong> leeg zijn. Zo krijg je bijvoorbeeld uit de rij<strong>en</strong> 1, 2, 4, 7 <strong>en</strong> 3, 5, 6, 8<br />

de rij 1, 2, 3, 4, 5, 6, 7, 8. Elke keer als je dit stukje programma uitvoert, is de l<strong>en</strong>gte <strong>van</strong> de resulter<strong>en</strong>de rij<br />

twee keer zo groot als de vorige keer. De hele executie <strong>van</strong> mergesort voegt n/2 rij<strong>en</strong> <strong>van</strong> l<strong>en</strong>gte 1 sam<strong>en</strong> tot<br />

n/4 rij<strong>en</strong> <strong>van</strong> l<strong>en</strong>gte 2 die word<strong>en</strong> sam<strong>en</strong>gevoegd tot n/8 rij<strong>en</strong> <strong>van</strong> l<strong>en</strong>gte 4 eindig<strong>en</strong>d in het sam<strong>en</strong>voeg<strong>en</strong><br />

<strong>van</strong> 2 rij<strong>en</strong> <strong>van</strong> l<strong>en</strong>gte n/2 (ev<strong>en</strong> uitgaande <strong>van</strong> het gunstige geval dat n e<strong>en</strong> macht <strong>van</strong> 2 is). Om te bepal<strong>en</strong><br />

wat de totale complexiteit <strong>van</strong> het steeds sam<strong>en</strong>voeg<strong>en</strong> <strong>van</strong> twee rij<strong>en</strong> is, moet je dus die getall<strong>en</strong> bij elkaar<br />

30<br />


kunn<strong>en</strong> optell<strong>en</strong>, dus bijvoorbeeld kunn<strong>en</strong> uitrek<strong>en</strong><strong>en</strong> wat de som � log n<br />

i=1 2i is. In deze sectie zull<strong>en</strong> we e<strong>en</strong><br />

aantal truuks voor het sommer<strong>en</strong> <strong>van</strong> reeks<strong>en</strong> die de lezer waarschijnlijk eerder gezi<strong>en</strong> heeft, maar mogelijk<br />

weer verget<strong>en</strong> is, de revue lat<strong>en</strong> passer<strong>en</strong>. We beginn<strong>en</strong> met e<strong>en</strong> e<strong>en</strong>voudige.<br />

Bekijk de reeks<br />

�<br />

n−1<br />

x i = 1 + x + x 2 + . . . + x n−1 = (1 − x n )/(1 − x) voor x �= 1.<br />

i=0<br />

Dat dit waar is, is in te zi<strong>en</strong> door beide kant<strong>en</strong> met 1 − x te verm<strong>en</strong>igvuldig<strong>en</strong>. Met deze observatie kunn<strong>en</strong><br />

we e<strong>en</strong> antwoord krijg<strong>en</strong> op de vraag hoe groot �log n<br />

i=0 2i is, zoals we hierbov<strong>en</strong> zocht<strong>en</strong>, want het is gewoon<br />

deze reeks met x = 2 <strong>en</strong> log n gesubstitueerd voor n, er komt dus uit (1 − 2log n )/(1 − 2) = n. Omdat we<br />

deze reeks echter voor algem<strong>en</strong>e x hebb<strong>en</strong> opgelost kunn<strong>en</strong> we ook bepal<strong>en</strong> wat �n i=0 3i voor het geval dat<br />

we e<strong>en</strong> algortime hebb<strong>en</strong> waarbij volg<strong>en</strong>de slag<strong>en</strong> steeds drie keer zo lang zijn.<br />

E<strong>en</strong> reeks als deze laat zich gebruik<strong>en</strong> voor nog andere toepassing<strong>en</strong>. Stel e<strong>en</strong>s dat we niet 1 + x + x2 +<br />

. . . + xn−1 moet<strong>en</strong> uitrek<strong>en</strong><strong>en</strong>, maar 1 + 2x + 3x2 + . . . + (n − 1)xn−2 . Deze reeks is de afgeleide <strong>van</strong> de reeks<br />

1 + x + x2 + . . . + xn−1 <strong>en</strong> dus is de som ook de afgeleide <strong>van</strong> (1 − xn )/(1 − x) dus<br />

1 − nx n−1 + (n − 1)x n<br />

(1 − x) 2<br />

Voor machtreeks<strong>en</strong> geldt dat als we de som <strong>van</strong> de machtreeks k<strong>en</strong>n<strong>en</strong>, zeg bijvoorbeeld � anx n = f(x),<br />

dan k<strong>en</strong>n<strong>en</strong> we ook � nanx n−1 , want dat is de afgeleide <strong>van</strong> f(x), maar dan natuurlijk ook � nanx n want<br />

dat is weer xf ′ (x). Dus als de nde coëffici<strong>en</strong>t met n verm<strong>en</strong>igvuldigd wordt, dan verandert de som <strong>van</strong> f(x)<br />

naar x d<br />

dx f(x).<br />

Dit spel—neem de afgeleide <strong>en</strong> verm<strong>en</strong>igvuldig het resultaat weer terug met x—kunn<strong>en</strong> we herhal<strong>en</strong>.<br />

Immers als xf ′ (x) = � nanx n dan is xf ′′ (x) = � n 2 anx n−1 <strong>en</strong> is x 2 f ′′ (x) = � n 2 anx n . Met andere<br />

woord<strong>en</strong>, het verm<strong>en</strong>igvuldig<strong>en</strong> <strong>van</strong> de n-de coëffici<strong>en</strong>t met n 2 verandert de som <strong>van</strong> de reeks <strong>van</strong> f naar<br />

(x d<br />

dx )2 f(x). Algem<strong>en</strong>er: als we de n-de coëffici<strong>en</strong>t <strong>van</strong> e<strong>en</strong> machtreeks met n p verm<strong>en</strong>igvuldig<strong>en</strong>, dan<br />

verandert de som <strong>van</strong> de reeks <strong>van</strong> f naar (x d<br />

dx )p f(x). Vanwege het feit dat we eindige somm<strong>en</strong> kunn<strong>en</strong><br />

herord<strong>en</strong><strong>en</strong> in elke volgorde die we will<strong>en</strong>, geldt dit voor algem<strong>en</strong>e polynom<strong>en</strong>. Als we bijvoorbeeld de<br />

coëffici<strong>en</strong>t <strong>van</strong> x n verm<strong>en</strong>igvuldig<strong>en</strong> met 5n 3 + n 2 + 4, dan verandert de som <strong>van</strong> f(x) naar (5(x d<br />

dx )3 +<br />

(x d<br />

dx )2 + 4)f(x). De algem<strong>en</strong>e regel voor e<strong>en</strong> willekeurig polynoom P is als volgt.<br />

�<br />

P (j)ajx j = P<br />

j<br />

.<br />

�<br />

x d<br />

�<br />

�<br />

dx<br />

In plaats <strong>van</strong> x i als sommand kunn<strong>en</strong> we ook te mak<strong>en</strong> krijg<strong>en</strong> met i x . Het bek<strong>en</strong>dste voorbeeld is wel<br />

1 + 2 + 3 + 4 + . . . + n = n(n + 1)/2 dat veelvuldig gebruikt wordt om bewijz<strong>en</strong> met inductie te illustrer<strong>en</strong>.<br />

Niet iedere<strong>en</strong> k<strong>en</strong>t echter de veralgem<strong>en</strong>isering <strong>van</strong> dit voorbeeld: � n<br />

i=0 i3 = (n(n + 1)) 2 /4. Dit geldt veel<br />

algem<strong>en</strong>er. Stel dat we (zie som 5) de beschikking hebb<strong>en</strong> over de volg<strong>en</strong>de stelling.<br />

Stelling 1.4.2 Als p e<strong>en</strong> polynoom in i <strong>van</strong> graad d is, dan is �n i=0 p(i) e<strong>en</strong> polynoom in n <strong>van</strong> graad d + 1.<br />

Nu kunn<strong>en</strong> we de bewering �n i=0 i3 = (n(n + 1)) 2 /4 bewijz<strong>en</strong> door te controler<strong>en</strong> dat n = 0, n = 1, n =<br />

2, n = 3 <strong>en</strong> n = 4 aan beide kant<strong>en</strong> respectievelijk 0, 1, 9, 36 <strong>en</strong> 100 oplever<strong>en</strong> omdat 5 punt<strong>en</strong> e<strong>en</strong> polynoom<br />

<strong>van</strong> de graad 4 volledig vastlegg<strong>en</strong>, maar dat niet alle<strong>en</strong>. We kunn<strong>en</strong> nu voor elk polynoom p achter de<br />

waarde <strong>van</strong> �n i=0 p(i) kom<strong>en</strong> door e<strong>en</strong> paar lineaire vergelijking<strong>en</strong> op te loss<strong>en</strong> die de coefficiënt<strong>en</strong> <strong>van</strong> het<br />

resulter<strong>en</strong>de polynoom bepal<strong>en</strong>.<br />

Voorbeeld 1.4.3: Berek<strong>en</strong><br />

n�<br />

2i 2 + 4.<br />

i=0<br />

31<br />

j<br />

ajxj


Figuur 1.5: De integraal <strong>en</strong> de som <strong>van</strong> log x.<br />

We wet<strong>en</strong> door Stelling 1.4.2 dat hier e<strong>en</strong> polynoom in n <strong>van</strong> graad 3 uit moet kom<strong>en</strong>. De algem<strong>en</strong>e vorm is<br />

an 3 +bn 2 +cn+d. Vier punt<strong>en</strong> <strong>van</strong> het polynoom zijn voldo<strong>en</strong>de om het uniek te bepal<strong>en</strong>. Voor n = 0, 1, 2, 3<br />

is de waarde <strong>van</strong> de som respectievelijk 4, 6, 12 <strong>en</strong> 22. We loss<strong>en</strong> op:<br />

Zodat we als som voor deze reeks vind<strong>en</strong><br />

d = 4<br />

a + b + c + d = 10<br />

8a + 4b + 2c + d = 22<br />

27a + 9b + 3c + d = 44<br />

2<br />

3 n3 + n 2 + 13<br />

n + 4.<br />

3<br />

T<strong>en</strong> slotte noem<strong>en</strong> we nog e<strong>en</strong> aantal voorbeeld<strong>en</strong> <strong>van</strong> somm<strong>en</strong> die vaak voorkom<strong>en</strong> <strong>en</strong> goed zijn om te<br />

k<strong>en</strong>n<strong>en</strong>.<br />

1.4.4 Reeks<strong>en</strong> <strong>en</strong> Integral<strong>en</strong><br />

e x = � ∞<br />

m=0 xm /m!<br />

sin x = � ∞<br />

r=0 (−1)r x 2r+1 /(2r + 1)!<br />

cos x = � ∞<br />

r=0 (−1)r x 2r /(2r)!<br />

log 1<br />

1−x = � ∞<br />

j+1 xj /j<br />

Integral<strong>en</strong> zijn in de wiskunde de infinitesimale vorm <strong>van</strong> sommer<strong>en</strong>. E<strong>en</strong> integraal geeft, zeer informeel<br />

gesprok<strong>en</strong>, e<strong>en</strong> uitdrukking <strong>van</strong> de oppervlakte <strong>van</strong> e<strong>en</strong> gebied onder e<strong>en</strong> functie doordat de som g<strong>en</strong>om<strong>en</strong><br />

wordt <strong>van</strong> oneindig veel rechthoek<strong>en</strong> <strong>van</strong> oneindig kleine dikte. We kunn<strong>en</strong> deze eig<strong>en</strong>schap, die in de analyse<br />

het integraalk<strong>en</strong>merk <strong>van</strong> d’Alembert” g<strong>en</strong>oemd wordt, gebruik<strong>en</strong> om somm<strong>en</strong> af te schatt<strong>en</strong>. Kijk<br />

”<br />

bijvoorbeeld e<strong>en</strong>s naar de functie f(x) = log x. Figuur 1.5 laat twee plots voor deze functie zi<strong>en</strong>, waarbij<br />

de waard<strong>en</strong> tuss<strong>en</strong> 1 <strong>en</strong> 10 op twee manier<strong>en</strong> als e<strong>en</strong> staafdiagram zijn weergegev<strong>en</strong>. De som <strong>van</strong> de functiewaard<strong>en</strong><br />

(verm<strong>en</strong>igvuldigd met 1 maar dat kun je niet zi<strong>en</strong>) geeft op twee manier<strong>en</strong> e<strong>en</strong> schatting <strong>van</strong> de<br />

waarde <strong>van</strong> de oppervlakte onder de functie, ofwel de oppervlakte <strong>van</strong> de functie geeft op twee manier<strong>en</strong><br />

e<strong>en</strong> schatting <strong>van</strong> de som <strong>van</strong> de functiewaard<strong>en</strong>. Nem<strong>en</strong> we de functiewaard<strong>en</strong> <strong>van</strong> 1 t.e.m. 9 dan zi<strong>en</strong> we<br />

dat de som e<strong>en</strong> onderschatting is <strong>van</strong> de integraal—ofwel de integraal is groter dan deze som, terwijl de<br />

functiewaard<strong>en</strong> <strong>van</strong> 2 t.e.m. 10 e<strong>en</strong> bov<strong>en</strong>schatting zijn <strong>van</strong> de integraal—ofwel de integraal is kleiner dan de<br />

som. Deze eig<strong>en</strong>schap kunn<strong>en</strong> we uiteraard gebruik<strong>en</strong> om de afschatting <strong>van</strong> e<strong>en</strong> reeks te krijg<strong>en</strong>, wanneer<br />

we de integraal wel k<strong>en</strong>n<strong>en</strong> maar de som niet. In het geval <strong>van</strong> log x is de integraal xlogx − x, dus als we e<strong>en</strong><br />

afschatting will<strong>en</strong> hebb<strong>en</strong> <strong>van</strong> bijvoorbeeld �n i=1 log i dan wet<strong>en</strong> we dat θ(n log n) e<strong>en</strong> geschikte afschatting<br />

is.<br />

32<br />


1.4.5 Somm<strong>en</strong><br />

1. Rondom e<strong>en</strong> cirkel staan 2n null<strong>en</strong> <strong>en</strong> één<strong>en</strong>, n <strong>van</strong> elke soort. Bewijs met inductie dat het altijd<br />

mogelijk is e<strong>en</strong> punt te vind<strong>en</strong> zó dat als je e<strong>en</strong> volledige cirkel met de klok meedraait, je op elk punt<br />

<strong>van</strong> de draai minst<strong>en</strong>s ev<strong>en</strong>veel null<strong>en</strong> als één<strong>en</strong> gezi<strong>en</strong> hebt.<br />

2. Los de volg<strong>en</strong>de recurr<strong>en</strong>te betrekking<strong>en</strong> op.<br />

(a)<br />

(b)<br />

(c)<br />

(d)<br />

(e)<br />

tn =<br />

� n als n = 0 of n = 1<br />

5tn−1 − 6tn−2 anders<br />

�<br />

2 9n − 15n + 106 als n = 0 of n = 1 of n = 2<br />

tn =<br />

tn−1 + 2tn−2 − 2tn−3 anders<br />

�<br />

n als n = 0 of n = 1 of n = 2<br />

tn =<br />

tn =<br />

tn−1 + tn−3 − tn−4 anders<br />

� n + 1 als n = 0 of n = 1<br />

3tn−1 − 2tn−2 + 3 × 2 n−2 anders<br />

tn =<br />

� 0 als n = 0<br />

1/(4 − tn − 1) anders<br />

3. Laat S e<strong>en</strong> verzameling <strong>van</strong> n lijn<strong>en</strong> zijn waar<strong>van</strong> ge<strong>en</strong> twee parallel zijn <strong>en</strong> ge<strong>en</strong> drie in hetzelfde punt<br />

snijd<strong>en</strong>. Bewijs met inductie dat de lijn<strong>en</strong> <strong>van</strong> S in θ(n) punt<strong>en</strong> snijd<strong>en</strong>.<br />

4. Berek<strong>en</strong><br />

(a) �n−1 i=0 i × ni<br />

(b) �n i=0 i3 + 2i2 + 4<br />

(c) �n i=0 (i3 + 2i2 + i)xi 5. Bewijs met volledige inductie dat als p e<strong>en</strong> polynoom in i <strong>van</strong> graad d is, dan is �n in n <strong>van</strong> graad d + 1 (Stelling 1.4.2).<br />

6. Geef schatting<strong>en</strong> voor � n<br />

i=1 ⌈logi⌉ <strong>en</strong> � n<br />

i=1 ⌈log(n/i)⌉.<br />

33<br />

i=0<br />

p(i) e<strong>en</strong> polynoom


Hoofdstuk 2<br />

Techniek<strong>en</strong><br />

In dit hoofdstuk bekijk<strong>en</strong> we e<strong>en</strong> aantal veelgebruikte techniek<strong>en</strong> om te kom<strong>en</strong> tot efficiënte algoritm<strong>en</strong><br />

voor problem<strong>en</strong>. We mak<strong>en</strong> e<strong>en</strong> indeling naar de aard <strong>van</strong> de algoritme die voor het probleem wordt<br />

besprok<strong>en</strong>. Sommige <strong>van</strong> de algoritm<strong>en</strong> in dit hoofdstuk zoud<strong>en</strong> met ev<strong>en</strong>veel recht in het volg<strong>en</strong>de hoofdstuk,<br />

Graf<strong>en</strong>algoritm<strong>en</strong>, kunn<strong>en</strong> word<strong>en</strong> geplaatst, omdat ze specifiek voor graf<strong>en</strong>problem<strong>en</strong> zijn ontworp<strong>en</strong>. De<br />

keuze om ze in dit hoofdstuk te behandel<strong>en</strong> is arbitrair.<br />

2.1 Gulzige <strong>Algoritm<strong>en</strong></strong><br />

De eerste soort algoritm<strong>en</strong> die we zull<strong>en</strong> bekijk<strong>en</strong> zijn optimalisatie algoritm<strong>en</strong>. Bij optimalisatiealgoritm<strong>en</strong> is<br />

altijd sprake <strong>van</strong> verschill<strong>en</strong>de mogelijke uitkomst<strong>en</strong> waar<strong>van</strong> er één of meer als beste kan word<strong>en</strong> aangemerkt.<br />

Bijvoorbeeld:<br />

1. Er zijn mogelijke pad<strong>en</strong> tuss<strong>en</strong> A <strong>en</strong> B, <strong>en</strong> het pad dat in l<strong>en</strong>gte het kortst is vind<strong>en</strong> wij het beste,<br />

2. uit hop <strong>en</strong> water kunn<strong>en</strong> we verschill<strong>en</strong>de soort<strong>en</strong> <strong>en</strong> hoeveelhed<strong>en</strong> bier mak<strong>en</strong> <strong>en</strong> de verdeling die het<br />

meeste geld oplevert vind<strong>en</strong> wij het beste,<br />

3. e<strong>en</strong> verzameling buss<strong>en</strong> kan langs e<strong>en</strong> verzameling sted<strong>en</strong> rijd<strong>en</strong> <strong>en</strong> het schema waarbij de totale reisl<strong>en</strong>gte<br />

<strong>van</strong> alle passagiers zo klein mogelijk gehoud<strong>en</strong> wordt, vind<strong>en</strong> wij het best.<br />

E<strong>en</strong> aanpak die altijd werkt voor optimalisatiealgoritm<strong>en</strong> is het bekijk<strong>en</strong> <strong>van</strong> alle mogelijke oplossing<strong>en</strong><br />

<strong>en</strong> daaruit de oplossing(<strong>en</strong>) te kiez<strong>en</strong> die het beste resultaat gev<strong>en</strong>. Deze uitputt<strong>en</strong>de methode (exhaustive<br />

search) kan echter soms heel duur zijn. Als we het grootste getal will<strong>en</strong> vind<strong>en</strong> dat in n bits geschrev<strong>en</strong><br />

kan word<strong>en</strong>, kunn<strong>en</strong> we alle getall<strong>en</strong> <strong>van</strong> n bits onder elkaar schrijv<strong>en</strong> <strong>en</strong> de grootste noter<strong>en</strong>, dat kost 2 n<br />

stapp<strong>en</strong>. Er zijn snellere method<strong>en</strong> d<strong>en</strong>kbaar, <strong>en</strong> één <strong>van</strong> die method<strong>en</strong> is de gulzige methode (of Greedy<br />

Method).<br />

We noem<strong>en</strong> e<strong>en</strong> optimalisatiealgoritme ”Gulzig” of ” Greedy” als ze de volg<strong>en</strong>de karakteristiek<strong>en</strong> heeft.<br />

- E<strong>en</strong> optimale oplossing wordt stap voor stap opgebouwd.<br />

- E<strong>en</strong> éénmaal g<strong>en</strong>om<strong>en</strong> stap wordt nooit ongedaan gemaakt.<br />

- In iedere stap wordt e<strong>en</strong> zo groot of zo goed mogelijk tuss<strong>en</strong>resultaat behaald.<br />

Gulzige method<strong>en</strong> zijn vaak niet moeilijk om te bed<strong>en</strong>k<strong>en</strong>. Het is de formule ” grote stapp<strong>en</strong> gauw thuis”<br />

<strong>en</strong> dus lijkt het op wat e<strong>en</strong> m<strong>en</strong>s als eerste g<strong>en</strong>eigd is om te do<strong>en</strong> als de situatie onoverzichtelijk is. E<strong>en</strong><br />

gulzige methode is ook bijzonder efficiënt omdat je nooit e<strong>en</strong> verkeerd pad inslaat. Veel moeilijker is het<br />

om te bewijz<strong>en</strong> dat de gulzige methode ook tot de optimale oplossing leidt, omdat er talloze problem<strong>en</strong><br />

zijn waarvoor helemaal ge<strong>en</strong> gulzige algoritm<strong>en</strong> (kunn<strong>en</strong>) bestaan. Vaak leidt de weg die het gunstigst lijkt<br />

35


verderop tot e<strong>en</strong> uitzichtloze situatie. We zull<strong>en</strong> e<strong>en</strong> aantal voorbeeld<strong>en</strong> <strong>van</strong> problem<strong>en</strong> beschrijv<strong>en</strong> waarin<br />

gulzige algoritm<strong>en</strong> tot e<strong>en</strong> optimale oplossing leid<strong>en</strong>.<br />

Lat<strong>en</strong> we eerst e<strong>en</strong>s ons triviale getall<strong>en</strong>voorbeeld bekijk<strong>en</strong>: we wet<strong>en</strong> dat bij éénbits getall<strong>en</strong> e<strong>en</strong> 1 groter<br />

is dan e<strong>en</strong> 0. Als we dus e<strong>en</strong> keuze moet<strong>en</strong> mak<strong>en</strong> om e<strong>en</strong> 1 of e<strong>en</strong> 0 in te vull<strong>en</strong> <strong>en</strong> we will<strong>en</strong> e<strong>en</strong> zo groot<br />

mogelijk getal hebb<strong>en</strong>, dan kiez<strong>en</strong> we voor de 1. In plaats <strong>van</strong> alle 2 n getall<strong>en</strong> op te schrijv<strong>en</strong> kunn<strong>en</strong> we ook<br />

e<strong>en</strong> groot n bits getal mak<strong>en</strong> door bij ieder bit de best mogelijke keuze te do<strong>en</strong>. Voor het eerste bit wet<strong>en</strong><br />

we dat e<strong>en</strong> 1 groter is dan e<strong>en</strong> 0 <strong>en</strong> we kiez<strong>en</strong> dus 1, voor het tweede bit geldt hetzelfde, voor het derde bit<br />

ook <strong>en</strong>zovoort. Als grootste n-bits getal krijg<strong>en</strong> we met deze keuz<strong>en</strong> <strong>van</strong>zelf 11 . . . 1.<br />

Dit lijkt allemaal e<strong>en</strong>voudiger dan het is. Niet in alle gevall<strong>en</strong> kunn<strong>en</strong> we e<strong>en</strong> globaal optimum bereik<strong>en</strong><br />

door steeds locaal e<strong>en</strong> optimale stap te kiez<strong>en</strong>. Als we bijvoorbeeld <strong>van</strong> <strong>Amsterdam</strong> naar Saarbrueck<strong>en</strong> (Dld)<br />

will<strong>en</strong> rijd<strong>en</strong> met de auto kunn<strong>en</strong> we zowel bij Arnhem als bij Maastricht de gr<strong>en</strong>s over. Arnhem is aanmerkelijk<br />

dichterbij <strong>Amsterdam</strong> dan Maastricht, toch is de keuze voor Arnhem de verkeerde als we zo snel<br />

mogelijk bij ons doel will<strong>en</strong> zijn. In dit geval is dus de keuze <strong>van</strong> het dichtstbijzijnde tuss<strong>en</strong>station niet goed<br />

g<strong>en</strong>oeg om ook de kortste weg te vind<strong>en</strong>. In 2.1.3 zull<strong>en</strong> we nog uitgebreid besprek<strong>en</strong> wat wel e<strong>en</strong> goede<br />

manier is om de kortste weg <strong>van</strong> A naar B te vind<strong>en</strong>.<br />

Om <strong>van</strong> e<strong>en</strong> probleem aan te ton<strong>en</strong> dat er e<strong>en</strong> gulzige algoritme voor bestaat zull<strong>en</strong> we e<strong>en</strong> eig<strong>en</strong>schap <strong>van</strong><br />

het probleem moet<strong>en</strong> vind<strong>en</strong> die het mogelijk maakt gedeeltelijke oplossing<strong>en</strong> steeds uit te breid<strong>en</strong> totdat we<br />

e<strong>en</strong> optimale oplossing voor het hele probleem gevond<strong>en</strong> hebb<strong>en</strong>. Hier<strong>van</strong> zull<strong>en</strong> we dan moet<strong>en</strong> bewijz<strong>en</strong><br />

dat de keuze die we mak<strong>en</strong> bij het uitbreid<strong>en</strong> <strong>van</strong> de deeloplossing steeds leidt tot e<strong>en</strong> optimale oplossing.<br />

We bekijk<strong>en</strong> e<strong>en</strong> paar voorbeeld<strong>en</strong>.<br />

2.1.1 Geld Wissel<strong>en</strong><br />

We beginn<strong>en</strong> met e<strong>en</strong> algoritme die elke cassiëre <strong>van</strong> de lokale supermarkt beheerst. Het probleem is het<br />

teruggev<strong>en</strong> <strong>van</strong> wisselgeld, waarbij het aantal bankbiljett<strong>en</strong> <strong>en</strong> muntstukk<strong>en</strong> dat moet word<strong>en</strong> teruggegev<strong>en</strong><br />

wordt geminimaliseerd. In ons muntsysteem is het allereerst zo dat elk bedrag dat moet word<strong>en</strong> teruggegev<strong>en</strong><br />

kan word<strong>en</strong> gemaakt, omdat in ons muntsysteem de e<strong>en</strong>heid zit. In het geval <strong>van</strong> de euro is de e<strong>en</strong>heid de<br />

euroc<strong>en</strong>t. Om verschill<strong>en</strong>de red<strong>en</strong> is die euroc<strong>en</strong>t uit het systeem gehaald, maar alle af te rek<strong>en</strong><strong>en</strong> bedrag<strong>en</strong><br />

word<strong>en</strong> vervolg<strong>en</strong>s afgerond op vijf c<strong>en</strong>t, zodat de vijf c<strong>en</strong>t munt de rol <strong>van</strong> de e<strong>en</strong>heid gaat vervull<strong>en</strong>.<br />

Als we de bedrag<strong>en</strong> die moet<strong>en</strong> word<strong>en</strong> teruggegev<strong>en</strong> vorm<strong>en</strong> uit uitsluit<strong>en</strong>d vijf euroc<strong>en</strong>t munt<strong>en</strong>, dan is<br />

het onmiddelijk duidelijk dat het aantal munt<strong>en</strong> dat wordt teruggegev<strong>en</strong> niet minimaal is. E<strong>en</strong> oplossing zou<br />

kunn<strong>en</strong> zijn, om eerst het terug te gev<strong>en</strong> bedrag uit vijf c<strong>en</strong>t munt<strong>en</strong> te mak<strong>en</strong>, <strong>en</strong> vervolg<strong>en</strong>s die munt<strong>en</strong><br />

“in te wissel<strong>en</strong>” voor grotere, net zo lang tot dat niet meer kan. Dit zou echter tot problem<strong>en</strong> kunn<strong>en</strong> leid<strong>en</strong><br />

aangezi<strong>en</strong> eerder g<strong>en</strong>om<strong>en</strong> beslissing<strong>en</strong>, latere beslissing<strong>en</strong> zoud<strong>en</strong> kunn<strong>en</strong> beïnvloed<strong>en</strong>. Bijvoorbeeld twee<br />

vijf c<strong>en</strong>t stukk<strong>en</strong> <strong>en</strong> één ti<strong>en</strong> c<strong>en</strong>t stuk mak<strong>en</strong> e<strong>en</strong> twintig c<strong>en</strong>t stuk, maar dat twintig c<strong>en</strong>t stuk kan ook uit<br />

twee ti<strong>en</strong> c<strong>en</strong>t stukk<strong>en</strong> gemaakt word<strong>en</strong>. De oplossing die door cassiëres gehanteerd wordt (<strong>en</strong> die ook leidt<br />

tot e<strong>en</strong> optimale oplossing) is die waarbij telk<strong>en</strong>s de grootste munte<strong>en</strong>heid die in het gat past dat gevuld<br />

moet word<strong>en</strong> daarin gestopt wordt, totdat er ge<strong>en</strong> gat meer over is. Deze algoritme werkt helaas niet in elk<br />

muntsysteem. Het muntsysteem moet ervoor ontworp<strong>en</strong> zijn om deze e<strong>en</strong>voudige manier <strong>van</strong> optimaliser<strong>en</strong><br />

mogelijk te mak<strong>en</strong>.<br />

2.1.2 Knapsack<br />

Het probleem is het vull<strong>en</strong> <strong>van</strong> e<strong>en</strong> rugzak met object<strong>en</strong> die allemaal e<strong>en</strong> eig<strong>en</strong> gewicht <strong>en</strong> e<strong>en</strong> eig<strong>en</strong> waarde<br />

hebb<strong>en</strong>. Als m<strong>en</strong> bijvoorbeeld gaat kamper<strong>en</strong>, dan is de t<strong>en</strong>t <strong>van</strong> waarde (afhankelijk <strong>van</strong> waar m<strong>en</strong> naartoe<br />

gaat uiteraard) maar het krat bier ook. Het gewicht <strong>van</strong> beide object<strong>en</strong> verschilt. Doorgaans zijn zwaardere<br />

object<strong>en</strong> waardevoller, maar niet altijd. De creditcard is zeer licht <strong>van</strong> gewicht, maar bij sommige bestemming<strong>en</strong><br />

onmisbaar. Als het totaal gewicht begr<strong>en</strong>sd is door één of andere waarde b, wat is dan de juiste<br />

combinatie <strong>van</strong> mee te nem<strong>en</strong> object<strong>en</strong>, zo dat de totale waarde gemaximaliseerd wordt?<br />

We beginn<strong>en</strong> e<strong>en</strong>voudig <strong>en</strong> nem<strong>en</strong> aan dat we niet altijd hele object<strong>en</strong> mee hoev<strong>en</strong> nem<strong>en</strong>. Koffie bijvoorbeeld<br />

laat zich tot ongeveer elk deel verdel<strong>en</strong> <strong>en</strong> <strong>van</strong> e<strong>en</strong> voorraad koffie kunn<strong>en</strong> we dus besluit<strong>en</strong> e<strong>en</strong> aantal<br />

gram mee te nem<strong>en</strong>. Hetzelfde geldt voor water, geld, etc. Om ons probleem e<strong>en</strong>voudig te mak<strong>en</strong> nem<strong>en</strong> we<br />

36


dit aan voor alle mee te nem<strong>en</strong> object<strong>en</strong>. Elk object heeft dus e<strong>en</strong> bepaald gewicht <strong>en</strong> e<strong>en</strong> bepaalde waarde.<br />

E<strong>en</strong> gulzige algoritme kan dus op deze gewicht<strong>en</strong> <strong>en</strong> waard<strong>en</strong> in elke stap selecter<strong>en</strong> <strong>en</strong> net zo lang kiez<strong>en</strong><br />

tot de gr<strong>en</strong>s is bereikt. Volg<strong>en</strong>s onze aanname kunn<strong>en</strong> we <strong>van</strong> elk object e<strong>en</strong> deel me<strong>en</strong>em<strong>en</strong>, dus de gr<strong>en</strong>s<br />

die gesteld is kan altijd precies word<strong>en</strong> bereikt. Er zijn twee voor de hand ligg<strong>en</strong>de keuz<strong>en</strong>.<br />

1. We kunn<strong>en</strong> zoveel mogelijk object<strong>en</strong> <strong>van</strong> zo klein mogelijk gewicht me<strong>en</strong>em<strong>en</strong>. Daarmee kunn<strong>en</strong> we<br />

veel object<strong>en</strong> in de rugzak stek<strong>en</strong> <strong>en</strong> dus de totale waarde <strong>van</strong> de rugzak groot mak<strong>en</strong>.<br />

2. We kunn<strong>en</strong> in elke stap e<strong>en</strong> object met e<strong>en</strong> zo groot mogelijke waarde kiez<strong>en</strong>. Dan vull<strong>en</strong> we de rugzak<br />

met zeer waardevolle object<strong>en</strong> <strong>en</strong> krijg<strong>en</strong> we ook e<strong>en</strong> totale waarde die groot is.<br />

Beide aanpakk<strong>en</strong> werk<strong>en</strong> niet. Om dat aan te ton<strong>en</strong> bekijk<strong>en</strong> we twee kleine voorbeeld<strong>en</strong>.<br />

Voorbeeld 1 geeft aan dat het kiez<strong>en</strong> <strong>van</strong> e<strong>en</strong> zo klein mogelijk gewicht niet goed is. Neem als voorbeeld<br />

e<strong>en</strong> gewichtsgr<strong>en</strong>s 5 <strong>en</strong> 3 object<strong>en</strong> met gewicht<strong>en</strong> 2,2,5 <strong>en</strong> waard<strong>en</strong> 2, 2, 10. Kiez<strong>en</strong> voor het kleinste gewicht<br />

eerst zal leid<strong>en</strong> tot het me<strong>en</strong>em<strong>en</strong> <strong>van</strong> object<strong>en</strong> 1, 2 <strong>en</strong> 1/5e <strong>van</strong> object 3 voor e<strong>en</strong> totale waarde <strong>van</strong><br />

2 + 2 + 2 = 6, terwijl het me<strong>en</strong>em<strong>en</strong> <strong>van</strong> alle<strong>en</strong> object 3 e<strong>en</strong> waarde 10 oplevert.<br />

Voorbeeld 2 geeft aan dat het kiez<strong>en</strong> <strong>van</strong> het object met de grootste waarde niet altijd goed is. Als we<br />

weer e<strong>en</strong> gewichtsgr<strong>en</strong>s 5 hebb<strong>en</strong> <strong>en</strong> nu 3 object<strong>en</strong> met waarde 5,4,3 <strong>en</strong> gewicht 5,3,2 dan krijgt de rugzak<br />

e<strong>en</strong> totale waarde 5 als we alle<strong>en</strong> object 1 me<strong>en</strong>em<strong>en</strong>, maar de rugzak krijgt waarde 7 als we object<strong>en</strong> 2<br />

<strong>en</strong> 3 me<strong>en</strong>em<strong>en</strong>. De oplossing is hier dat we de object<strong>en</strong> moet<strong>en</strong> rangschikk<strong>en</strong> naar oplop<strong>en</strong>de waarde per<br />

gewichtse<strong>en</strong>heid <strong>en</strong> dan eerst het object kiez<strong>en</strong> dat de grootste waarde per gewichtse<strong>en</strong>heid heeft. In het<br />

eerste geval leidt dat tot e<strong>en</strong> ord<strong>en</strong>ing: 1, 1, 2, wat inhoudt dat we eerst zull<strong>en</strong> kiez<strong>en</strong> voor zoveel mogelijk<br />

me<strong>en</strong>em<strong>en</strong> <strong>van</strong> object 3 <strong>en</strong> in het tweede geval leidt dat tot e<strong>en</strong> ord<strong>en</strong>ing 1, 4/3, 3/2, waardoor we eerst voor<br />

object 3, <strong>en</strong> daarna voor object 2 zull<strong>en</strong> kiez<strong>en</strong>, waarna de rugzak vol is. Deze strategie leidt ook in het<br />

algeme<strong>en</strong> tot e<strong>en</strong> optimale oplossing. Dit zull<strong>en</strong> we bewijz<strong>en</strong> in Opgave 3.<br />

2.1.3 Graf<strong>en</strong>: kortste pad<strong>en</strong><br />

Het probleem is het vind<strong>en</strong> <strong>van</strong> het kortste pad in e<strong>en</strong> gewog<strong>en</strong> graaf. Gegev<strong>en</strong> is dus e<strong>en</strong> graaf G = (V, E)<br />

met E ⊆ V × V , e<strong>en</strong> gewichtsfunctie f : E ↦→ R+ (alle<strong>en</strong> positieve gewicht<strong>en</strong>) <strong>en</strong> e<strong>en</strong> speciaal startpunt S<br />

in de graaf, <strong>en</strong> gevraagd is voor elk punt A in de graaf de l<strong>en</strong>gte <strong>van</strong> e<strong>en</strong> pad <strong>van</strong> S naar A te vind<strong>en</strong> zo dat<br />

de som <strong>van</strong> de gewicht<strong>en</strong> <strong>van</strong> de kant<strong>en</strong> in dat pad minimaal is. Ook voor dit probleem bestaat e<strong>en</strong> gulzige<br />

algoritme, bedacht door E.W. Dijkstra in 1959 die in de praktijk nog steeds gebruikt wordt in bijvoorbeeld<br />

routeplanners. E<strong>en</strong> voor de hand ligg<strong>en</strong>de gulzige strategie zou zijn om eerst de kant met het kleinste gewicht<br />

te kiez<strong>en</strong> <strong>en</strong> <strong>van</strong> daaruit verder te werk<strong>en</strong>, maar e<strong>en</strong> zeer klein teg<strong>en</strong>voorbeeld laat zi<strong>en</strong> dat dat niet tot de<br />

optimale oplossing kan leid<strong>en</strong> (zie opgave 6). De aanpak die Dijkstra koos is de volg<strong>en</strong>de.<br />

Aan het begin <strong>van</strong> de algoritme is er precies één knoop waar<strong>van</strong> we met zekerheid kunn<strong>en</strong> zegg<strong>en</strong> wat de<br />

afstand tot S is, namelijk S zelf. Omdat alle afstand<strong>en</strong> in de graaf groter dan 0 zijn, kunn<strong>en</strong> we ge<strong>en</strong> korter<br />

pad naar S vind<strong>en</strong> dan het pad zonder kant<strong>en</strong>. De afstand <strong>van</strong> S tot S is dus met zekerheid 0. Dit wet<strong>en</strong>de,<br />

kunn<strong>en</strong> we <strong>van</strong> één andere knoop de afstand tot S bepal<strong>en</strong>. S heeft namelijk e<strong>en</strong> aantal bur<strong>en</strong> v1, v2, . . . , vk,<br />

die allemaal door e<strong>en</strong> kant met gewicht groter dan 0 met S verbond<strong>en</strong> zijn. Elk pad naar e<strong>en</strong> willekeurige<br />

knoop in de graaf (dus zeker naar v1, . . . , vk) gaat door één <strong>van</strong> deze knop<strong>en</strong>. Als dus vm e<strong>en</strong> buur <strong>van</strong> S is<br />

waar<strong>van</strong> het gewicht <strong>van</strong> de verbind<strong>en</strong>de kant minimaal is, dan kan er ge<strong>en</strong> pad in de graaf zijn dat korter<br />

is dan het gewicht <strong>van</strong> deze kant. Kortom vm vormt sam<strong>en</strong> met S e<strong>en</strong> groep knop<strong>en</strong> waar<strong>van</strong> we de afstand<br />

tot S in de graaf wet<strong>en</strong>. Noem deze groep knop<strong>en</strong> W . De algoritme breidt nu stap voor stap de verzameling<br />

W uit, totdat alle knop<strong>en</strong> in de graaf in W zitt<strong>en</strong>.<br />

Op elk mom<strong>en</strong>t geldt dat we, kijk<strong>en</strong>d naar de bur<strong>en</strong> <strong>van</strong> knop<strong>en</strong> in W , zi<strong>en</strong> dat we één <strong>van</strong> deze knop<strong>en</strong><br />

ook het kortste pad in de graaf wet<strong>en</strong>. Dat is namelijk <strong>van</strong> de knoop, v, waar<strong>van</strong> de afstand tot S, uitsluit<strong>en</strong>d<br />

via knop<strong>en</strong> in W , minimaal is. Immers, als het korste pad <strong>van</strong> S naar v niet uitsluit<strong>en</strong>d via knop<strong>en</strong> in W<br />

zou lop<strong>en</strong>, dan zou het via e<strong>en</strong> andere knoop w buit<strong>en</strong> W lop<strong>en</strong>. Laat w zonder beperking der algeme<strong>en</strong>heid<br />

de eerste knoop zijn die op het korste pad naar v ligt <strong>en</strong> niet in W zit. Dan loopt het pad <strong>van</strong> S naar w<br />

uitsluit<strong>en</strong>d door knop<strong>en</strong> in W , <strong>en</strong> is korter dan het pad dat uitsluit<strong>en</strong>d door knop<strong>en</strong> in W naar v loopt, want<br />

37


v �= w. Dat is in teg<strong>en</strong>spraak met de manier waarop v gekoz<strong>en</strong> is.<br />

Voorbeeld 2.1.1: Beschouw de volg<strong>en</strong>de graaf.<br />

3<br />

��<br />

9<br />

��<br />

��<br />

4<br />

2<br />

7<br />

3<br />

2<br />

1<br />

��<br />

2<br />

��<br />

1<br />

��<br />

S<br />

3<br />

5<br />

��<br />

5 �<br />

6<br />

��<br />

5 9<br />

De algoritme <strong>van</strong> Dijkstra vindt achtere<strong>en</strong>volg<strong>en</strong>s de volg<strong>en</strong>de afstand<strong>en</strong><br />

S 1 2 3 4 5 6 7 8 9 W<br />

0 1 ∞ ∞ ∞ ∞ 3 ∞ ∞ 5 {S}<br />

0 1 3 ∞ 8 ∞ 3 ∞ ∞ 5 {S, 1}<br />

0 1 3 ∞ 8 ∞ 3 5 4 5 {S, 1, 6}<br />

0 1 3 5 8 ∞ 3 5 4 5 {S, 1, 6, 2}<br />

0 1 3 5 8 ∞ 3 5 4 5 {S, 1, 6, 2, 8}<br />

0 1 3 5 8 ∞ 3 5 4 5 {S, 1, 6, 2, 8, 3}<br />

0 1 3 5 8 ∞ 3 5 4 5 {S, 1, 6, 2, 8, 3, 7}<br />

0 1 3 5 8 ∞ 3 5 4 5 {S, 1, 6, 2, 8, 3, 7, 9}<br />

0 1 3 5 8 11 3 5 4 5 {S, 1, 6, 2, 8, 3, 7, 9, 4}<br />

0 1 3 5 8 11 3 5 4 5 {S, 1, 6, 2, 8, 3, 7, 9, 4, 5}<br />

2.1.4 Graf<strong>en</strong>: opspann<strong>en</strong>de bom<strong>en</strong><br />

E<strong>en</strong> opspann<strong>en</strong>de boom in e<strong>en</strong> gewog<strong>en</strong> graaf is e<strong>en</strong> deelverzameling <strong>van</strong> de kant<strong>en</strong> die sam<strong>en</strong> e<strong>en</strong> boom<br />

vorm<strong>en</strong> waarin alle knop<strong>en</strong> zijn opg<strong>en</strong>om<strong>en</strong>. Deze boom is niet noodzakelijk geworteld. De meest voor de<br />

hand ligg<strong>en</strong>de toepassing <strong>van</strong> e<strong>en</strong> opspann<strong>en</strong>de boom is die <strong>van</strong> de netwerk (bijvoorbeeld telefoon) verbinding.<br />

Tuss<strong>en</strong> e<strong>en</strong> aantal punt<strong>en</strong> <strong>van</strong> het vlak zijn verbinding<strong>en</strong> mogelijk, ieder met hun eig<strong>en</strong> kost<strong>en</strong>. Het vind<strong>en</strong><br />

<strong>van</strong> e<strong>en</strong> opspann<strong>en</strong>de boom is dan het vind<strong>en</strong> <strong>van</strong> e<strong>en</strong> deelverzameling <strong>van</strong> de kant<strong>en</strong> zo dat elk <strong>van</strong> de<br />

punt<strong>en</strong> door middel <strong>van</strong> e<strong>en</strong> pad met elk ander punt verbond<strong>en</strong> is, maar niet door twee pad<strong>en</strong>. De kunst<br />

<strong>van</strong> de optimalisatie is hier natuurlijk het vind<strong>en</strong> <strong>van</strong> e<strong>en</strong> opspann<strong>en</strong>de boom waar<strong>van</strong> het totale gewicht<br />

minimaal is, de zog<strong>en</strong>oemde mincost spanning tree. Er zijn twee bek<strong>en</strong>de gulzige algoritm<strong>en</strong> voor het vind<strong>en</strong><br />

<strong>van</strong> de opspann<strong>en</strong>de boom, vernoemd naar de uitvinders <strong>van</strong> deze algoritm<strong>en</strong>. Beide algoritm<strong>en</strong> start<strong>en</strong> met<br />

e<strong>en</strong> lege verzameling kant<strong>en</strong> <strong>en</strong> breid<strong>en</strong> deze verzameling uit totdat e<strong>en</strong> opspann<strong>en</strong>de boom <strong>van</strong> minimale<br />

kost<strong>en</strong> is gebouwd.<br />

De algoritme <strong>van</strong> Prim<br />

De opzet <strong>van</strong> de algoritme is simpel. Begin met de lege verzameling. Voeg e<strong>en</strong> kant <strong>van</strong> minimaal gewicht<br />

toe, dan hebb<strong>en</strong> we e<strong>en</strong> boom met 2 knop<strong>en</strong>. Als we e<strong>en</strong> boom met k knop<strong>en</strong> hebb<strong>en</strong>, kunn<strong>en</strong> we e<strong>en</strong> boom<br />

met k + 1 knop<strong>en</strong> krijg<strong>en</strong> door de minimale kant toe te voeg<strong>en</strong> die deze boom verbindt met e<strong>en</strong> knoop die<br />

nog niet in de boom zit. Zo breid<strong>en</strong> we de boom uit totdat alle knop<strong>en</strong> in de boom zijn opg<strong>en</strong>om<strong>en</strong>. Deze<br />

boom is ook <strong>van</strong> minimale kost<strong>en</strong>, maar dat zull<strong>en</strong> we voor beide algoritm<strong>en</strong> tegelijkertijd bewijz<strong>en</strong>.<br />

38<br />

2<br />

1<br />

�<br />

��<br />

7<br />

��<br />

8<br />

��<br />

8<br />


De algoritme <strong>van</strong> Kruskal<br />

Ook hier beginn<strong>en</strong> we met e<strong>en</strong> lege graaf <strong>en</strong> voeg<strong>en</strong> we kant<strong>en</strong> toe, te beginn<strong>en</strong> met de kant <strong>van</strong> minimaal<br />

gewicht. Ord<strong>en</strong> de kant<strong>en</strong> naar gewicht <strong>en</strong> voeg e<strong>en</strong> volg<strong>en</strong>de kant (in de ord<strong>en</strong>ing) aan de verzameling<br />

kant<strong>en</strong> toe als deze ge<strong>en</strong> cykel introduceert. Als de graaf waarmee je begint verbond<strong>en</strong> is, dan word<strong>en</strong> zo<br />

uiteindelijk alle knop<strong>en</strong> in de graaf met elkaar verbond<strong>en</strong>, <strong>en</strong> heb je e<strong>en</strong> opspann<strong>en</strong>de boom. In teg<strong>en</strong>stelling<br />

tot Prim’s algoritme mak<strong>en</strong> we ons niet druk om het bijhoud<strong>en</strong> <strong>van</strong> e<strong>en</strong> gedeelte <strong>van</strong> e<strong>en</strong> opspann<strong>en</strong>de boom,<br />

maar lat<strong>en</strong> we e<strong>en</strong> bos ontstaan dat langzaamaan tot e<strong>en</strong> <strong>en</strong>kele boom aan elkaar groeit.<br />

Correctheid<br />

Dat deze algoritm<strong>en</strong> correct zijn volgt uit het feit dat ze beide de volg<strong>en</strong>de invariant respecter<strong>en</strong>. op elk<br />

tijdstip is de opg<strong>en</strong>om<strong>en</strong> verzameling kant<strong>en</strong> deelverzameling <strong>van</strong> de verzameling kant<strong>en</strong> <strong>van</strong> e<strong>en</strong> minimale<br />

opspann<strong>en</strong>de boom. Merk op, er kan meer dan één minimale opspann<strong>en</strong>de boom zijn. We zull<strong>en</strong> lat<strong>en</strong> zi<strong>en</strong><br />

dat de invariant behoud<strong>en</strong> blijft m.b.v. e<strong>en</strong> inductief bewijs. Uiteraard is voor beide algoritm<strong>en</strong> de invariant<br />

gerespecteerd aan het begin <strong>van</strong> de uitvoering. Immers de verzameling kant<strong>en</strong> is leeg, <strong>en</strong> de lege verzameling<br />

is deelverzameling <strong>van</strong> elke verzameling. Stel nu e<strong>en</strong>s dat er erg<strong>en</strong>s in de algoritme e<strong>en</strong> punt t is waar de<br />

invariant niet meer gerespecteerd wordt, <strong>en</strong> neem aan dat we de eerste keer bekijk<strong>en</strong> dat e<strong>en</strong> kant e wordt<br />

opg<strong>en</strong>om<strong>en</strong> die niet elem<strong>en</strong>t is <strong>van</strong> <strong>en</strong>ige minimale opspann<strong>en</strong>de boom. De verzameling <strong>van</strong> kant<strong>en</strong> die tot<br />

tijdstip t − 1 was opg<strong>en</strong>om<strong>en</strong>, Et−1, was nog wel deelverzameling <strong>van</strong> e<strong>en</strong> minimale opspann<strong>en</strong>de boom, zeg<br />

Tt−1. Bekijk de verzameling T = Tt−1 ∪ {e}. Omdat Tt−1 e<strong>en</strong> boom is <strong>en</strong> e /∈ Tt−1 heeft T e<strong>en</strong> cykel.<br />

Laat Vt−1 de verzameling eindpunt<strong>en</strong> <strong>van</strong> Et−1 zijn. Er is minst<strong>en</strong>s één punt op de cykel dat niet in Vt−1<br />

zit. Immers e heeft maar één eindpunt in in Vt (Prim) of de opname <strong>van</strong> e in stap t introduceert ge<strong>en</strong> cykel<br />

(Kruskal). Er is dus e<strong>en</strong> kant e ′ in T die Vt−1 verbindt met de rest <strong>van</strong> de boom. Het gewicht <strong>van</strong> deze<br />

kant is minst<strong>en</strong>s zo groot als het gewicht <strong>van</strong> e, anders was e ′ in stap t gekoz<strong>en</strong>. Dit betek<strong>en</strong>t echter dat<br />

T − {e ′ } e<strong>en</strong> spanning tree is, waar<strong>van</strong> de kost<strong>en</strong> hoogst<strong>en</strong>s zo groot zijn als die <strong>van</strong> T − {e} (<strong>en</strong> die dus ook<br />

e<strong>en</strong> mincost spanning tree is) waar<strong>van</strong> e e<strong>en</strong> kant is.<br />

Voorbeeld 2.1.2: We gebruik<strong>en</strong> als voorbeeld de volg<strong>en</strong>de graaf.<br />

3<br />

4<br />

9<br />

2<br />

7<br />

3<br />

2<br />

1<br />

2<br />

2<br />

1<br />

0<br />

5<br />

3<br />

5<br />

3<br />

4<br />

5<br />

Met de beide besprok<strong>en</strong> algoritm<strong>en</strong> nem<strong>en</strong> we dan achtere<strong>en</strong>volg<strong>en</strong>s de volg<strong>en</strong>de knop<strong>en</strong> <strong>en</strong> kant<strong>en</strong> op.<br />

39<br />

1<br />

5<br />

6<br />

9<br />

2<br />

1<br />

3<br />

8<br />

7<br />

8


Prim Kruskal<br />

knoop kant gewicht<br />

0 - 0<br />

1 (0,1) 1<br />

2 (1,2) 3<br />

5 (0,5) 5<br />

3 (2,3) 7<br />

6 (0,6) 10<br />

8 (6,8) 11<br />

9 (6,9) 12<br />

7 (6,7) 14<br />

4 (5,4) 17<br />

knoop kant gewicht<br />

0 - 0<br />

1 (0,1) 1<br />

6,8 (6,8) 2<br />

9 (9,6) 3<br />

5 (5,0) 5<br />

2 (1,2) 7<br />

3 (2,3) 9<br />

7 (6,7) 11<br />

- (0,6) 14<br />

4 (4,5) 17<br />

Het toeval wil dat de algoritm<strong>en</strong> allebei dezelfde opspann<strong>en</strong>de boom oplever<strong>en</strong>, namelijk de volg<strong>en</strong>de.<br />

2.1.5 Scheduling<br />

2<br />

2<br />

2<br />

3 1<br />

4<br />

3<br />

1<br />

2<br />

0<br />

5<br />

3<br />

Bij het postkantoor staan m<strong>en</strong>s<strong>en</strong> in e<strong>en</strong> rij. Iedere<strong>en</strong> wil natuurlijk zo snel mogelijk uit de rij <strong>van</strong>daan <strong>en</strong><br />

daarom zou iedere<strong>en</strong> het eerst geholp<strong>en</strong> will<strong>en</strong> word<strong>en</strong>. Voor de beambte achter het loket zal het om het ev<strong>en</strong><br />

zijn wie eerst geholp<strong>en</strong> moet word<strong>en</strong>, want de totaal b<strong>en</strong>odigde tijd om iedere<strong>en</strong> te help<strong>en</strong> is niet afhankelijk<br />

<strong>van</strong> in welke volgorde de person<strong>en</strong> in de rij moet<strong>en</strong> word<strong>en</strong> geholp<strong>en</strong>. Toch maakt de volgorde iets uit omdat<br />

de verschill<strong>en</strong>de handeling<strong>en</strong> e<strong>en</strong> verschill<strong>en</strong>de hoeveelheid tijd kost<strong>en</strong>, <strong>en</strong> als de postzegels eerst verkocht<br />

word<strong>en</strong> dan moet de klant die het aangetek<strong>en</strong>de stuk wil verz<strong>en</strong>d<strong>en</strong> daar weliswaar op wacht<strong>en</strong>, maar als<br />

het aangetek<strong>en</strong>de stuk verzond<strong>en</strong> moet word<strong>en</strong>, moet de klant die de postzegels wil kop<strong>en</strong> dáár op wacht<strong>en</strong>.<br />

Kortom, behalve de nuttig bestede tijd die kan word<strong>en</strong> afgemet<strong>en</strong> aan de werktijd <strong>van</strong> de beambte—deze is<br />

naar wij aannem<strong>en</strong> altijd nuttig bezig—is er e<strong>en</strong> hoeveelheid onnuttig bestede tijd, namelijk die de klant<strong>en</strong><br />

op elkaar staan te wacht<strong>en</strong>. Ons eerste scheduling probleem is het minimaliser<strong>en</strong> <strong>van</strong> deze tijd.<br />

Voorbeeld 2.1.3: Laat drie tak<strong>en</strong> met hun tijdsduur gegev<strong>en</strong> zijn t1 = 5, t2 = 10 <strong>en</strong> t3 = 3. Er zijn zes<br />

mogelijke volgordes waarin deze tak<strong>en</strong> kunn<strong>en</strong> word<strong>en</strong> uitgevoerd.<br />

Volgorde Tijd<br />

123 5+(5+10)+(5+10+3)=38<br />

132 5+(5+3)+(5+3+10)=31<br />

213 10+(10+5)+(10+5+3)=43<br />

231 10+(10+3)+(10+3+5)=41<br />

312 3+(3+5)+(3+5+10)=29<br />

321 3+(3+10)+(3+10+5)=34<br />

40<br />

1<br />

6<br />

9<br />

2<br />

1<br />

7<br />

8<br />


In de eerste regel <strong>van</strong> dit voorbeeld is klant 1 het eerst aan de beurt, haar totale tijd in de rij is dus<br />

5, daarna komt klant 2 die eerst op klant 1 heeft moet<strong>en</strong> wacht<strong>en</strong> zodat haar totale tijd in de rij 15 is.<br />

T<strong>en</strong>slotte komt klant 3 die eerst op klant 1 <strong>en</strong> klant 2 heeft moet<strong>en</strong> wacht<strong>en</strong> zodat haar totale tijd in de rij 18<br />

is. In dit voorbeeld valt op dat de volgorde <strong>van</strong> behandel<strong>en</strong> waarbij de klant die het minste tijd vraagt het<br />

eerst behandeld wordt, de minste totale wachttijd oplevert. Mogelijk is dat ook de basis voor onze gulzige<br />

algoritme.<br />

We bewijz<strong>en</strong> dit als volgt. Laat P = p1, p2 . . . , pn e<strong>en</strong> permutatie zijn <strong>van</strong> 1, . . . , n <strong>en</strong> laat si = tpi —de<br />

tijd die taak pi nodig heeft—zijn. Als de tak<strong>en</strong> word<strong>en</strong> uitgevoerd in volgorde P dan is de totale tijd die<br />

nodig is om alle tak<strong>en</strong> uit te voer<strong>en</strong><br />

T (P ) = s1 + (s1 + s2) + (s1 + s2 + s3) + . . .<br />

= ns1 + (n − 1)s2 + (n − 2)s3 + . . .<br />

=<br />

(n − k + 1)sk<br />

� n<br />

k=1<br />

Stel dat P niet de tak<strong>en</strong> in volgorde <strong>van</strong> b<strong>en</strong>odigde tijd uitvoert, dan zijn er getall<strong>en</strong> a <strong>en</strong> b met a < b <strong>en</strong><br />

sa > sb. Als we alle<strong>en</strong> a <strong>en</strong> b verwissel<strong>en</strong>, dan krijg<strong>en</strong> we e<strong>en</strong> nieuwe volgorde P ′ met totale tijd<br />

We berek<strong>en</strong><strong>en</strong><br />

T (P ′ ) = (n − a − 1)sb + (n − b − 1)sa +<br />

n�<br />

(n − k + 1)sk.<br />

k=1<br />

k�=a,b<br />

T (P ) − T (P ′ ) = (n − a + 1)(sa − sb) + (n − b + 1)(sb − sa)<br />

= (b − a)(sa − sb) > 0<br />

Dus elk schema waarin e<strong>en</strong> twee tak<strong>en</strong> word<strong>en</strong> uitgevoerd die niet in oplop<strong>en</strong>de volgorde <strong>van</strong> de tijd staan<br />

die die tak<strong>en</strong> nodig hebb<strong>en</strong> is suboptimaal.<br />

Deadlines<br />

Allerlei verfijning<strong>en</strong> kunn<strong>en</strong> aan scheduling word<strong>en</strong> opgehang<strong>en</strong>. Eén <strong>van</strong> de meest gebruikelijke is dat tak<strong>en</strong><br />

niet onbegr<strong>en</strong>sd lang op elkaar kunn<strong>en</strong> wacht<strong>en</strong>. Aan elke taak kunn<strong>en</strong> we e<strong>en</strong> “deadline” hang<strong>en</strong>, dwz e<strong>en</strong><br />

tijdstip waarop de taak moet word<strong>en</strong> uitgevoerd om nog er nog profijt <strong>van</strong> te kunn<strong>en</strong> hebb<strong>en</strong>. We mak<strong>en</strong> de<br />

vere<strong>en</strong>voudiging dat elke taak nu slechts één e<strong>en</strong>heid tijd kost. Laat di de deadline voor taak i zijn, die als<br />

zij vóór de deadline wordt uitgevoerd profijt gi oplevert. Lat<strong>en</strong> we e<strong>en</strong>s naar de volg<strong>en</strong>de vier tak<strong>en</strong> kijk<strong>en</strong>.<br />

i 1 2 3 4<br />

gi 50 10 15 30<br />

di 2 1 2 1<br />

De deadlines in dit voorbeeld zijn zo strak gesteld dat er maar e<strong>en</strong> paar mogelijke manier<strong>en</strong> zijn om de<br />

tak<strong>en</strong> uit te voer<strong>en</strong>. De overgeblev<strong>en</strong> volgordes zi<strong>en</strong> er als volgt uit.<br />

Volgorde Opbr<strong>en</strong>gst Volgorde Opbr<strong>en</strong>gst<br />

1 50 2,1 60<br />

2 10 2,3 25<br />

3 15 3,1 65<br />

4 30 4,1 80<br />

1,3 65 4,3 45<br />

We noem<strong>en</strong> e<strong>en</strong> deelverzameling <strong>van</strong> de tak<strong>en</strong> uitvoerbaar als er e<strong>en</strong> volgorde is waarin elk <strong>van</strong> de tak<strong>en</strong> in<br />

deze deelverzameling kan word<strong>en</strong> uitgevoerd voor zijn deadline. E<strong>en</strong> voor de hand ligg<strong>en</strong>de gulzige algoritme<br />

om ons probleem op te loss<strong>en</strong> is nu—beginn<strong>en</strong>d met de lege verzameling—telk<strong>en</strong>s de taak met de grootste<br />

41<br />


opbr<strong>en</strong>st aan de verzameling toe te voeg<strong>en</strong> zodat de sam<strong>en</strong>gestelde verzameling uitvoerbaar blijft, totdat dit<br />

niet meer mogelijk is. In het voorbeeld zoud<strong>en</strong> we eerst taak 1 kiez<strong>en</strong> <strong>en</strong> daar vervolg<strong>en</strong>s taak 4 aan toe<br />

kunn<strong>en</strong> voeg<strong>en</strong> omdat de volgorde 4,1 uitvoerbaar is. De volg<strong>en</strong>de taak zou taak 3 zijn, maar {1, 3, 4} is niet<br />

uitvoerbaar <strong>en</strong> ook {1, 2, 4} is niet uitvoerbaar, dus deze algoritme eindigt met {1, 4}. Vindt deze algoritme<br />

altijd e<strong>en</strong> optimaal schema?<br />

Eerst merk<strong>en</strong> we op dat als we e<strong>en</strong> verzameling tak<strong>en</strong> hebb<strong>en</strong> dat uitvoerbaar is <strong>en</strong> we will<strong>en</strong> er e<strong>en</strong><br />

nieuwe taak aan toevoeg<strong>en</strong>, dat we dan niet alle permutaties hoev<strong>en</strong> na te gaan om te zi<strong>en</strong> of de nieuwe<br />

verzameling uitvoerbaar is. Dit weg<strong>en</strong>s de volg<strong>en</strong>de eig<strong>en</strong>schap.<br />

Als J e<strong>en</strong> verzameling <strong>van</strong> k tak<strong>en</strong> is, g<strong>en</strong>ummerd d1 ≤ . . . ≤ dk dan is J uitvoerbaar als <strong>en</strong><br />

alle<strong>en</strong> als de volgorde 1, 2, . . . , k uitvoerbaar is.<br />

Het is duidelijk dat de verzameling uitvoerbaar is als de volgorde 1, . . . , k uitvoerbaar is. Omgekeerd als<br />

1, 2, . . . , k niet uitvoerbaar is, dan wordt in die volgorde t<strong>en</strong>minste één taak na zijn deadline gepland. Als<br />

r zo’n taak is dan is dus dr ≤ r − 1. Aangezi<strong>en</strong> de tak<strong>en</strong> in de volgorde <strong>van</strong> niet-dal<strong>en</strong>de deadlines zijn<br />

gerangschikt betek<strong>en</strong>t dat dat t<strong>en</strong>minste r tak<strong>en</strong> e<strong>en</strong> deadline kleiner dan of gelijk aan r − 1 hebb<strong>en</strong>. Hoe je<br />

die ook rangschikt, er komt er dan altijd één te laat.<br />

De gulzige algoritme hierbov<strong>en</strong> geschetst vindt altijd de optimale volgorde.<br />

Stel dat deze algoritme één of andere volgorde I kiest die niet optimaal is. Er is e<strong>en</strong> andere volgorde J<br />

die wel optimaal is. Zet de volgordes SI <strong>en</strong> SJ onder elkaar, mogelijk met gat<strong>en</strong>. We herschikk<strong>en</strong> de tak<strong>en</strong><br />

in SI <strong>en</strong> SJ, ook mogelijk met gat<strong>en</strong>, zodat uitvoerbare volgordes S ′ I <strong>en</strong> S′ J ontstaan, waarin elke taak die S′ I<br />

<strong>en</strong> S ′ J voorkomt in S′ J recht onder dezelfde taak in S′ I staat. Dat dit kan is als volgt in te zi<strong>en</strong>. Stel dat taak<br />

a in SI <strong>en</strong> SJ voorkomt. op plaast<strong>en</strong> tI <strong>en</strong> tJ respectievelijk. Als tI = tJ is er niets te do<strong>en</strong>, stel daarom dat<br />

tI < tJ. De deadline voor a is niet eerder dan tJ. We kunn<strong>en</strong> nu a in SI verplaats<strong>en</strong> naar tJ. Als er in SI<br />

e<strong>en</strong> gat zit op plaats tJ, dan is er niets meer te do<strong>en</strong>. Als op plaats tJ e<strong>en</strong> taak b staat, dan verwissel<strong>en</strong> we<br />

a <strong>en</strong> b. De taak b wordt dan naar vor<strong>en</strong> gehaald in de volgorde, <strong>en</strong> dat kan zeker niet tot onuitvoerbaarheid<br />

leid<strong>en</strong>.<br />

Nu we aldus alle geme<strong>en</strong>schappelijke tak<strong>en</strong> op dezelfde plaats hebb<strong>en</strong> gezet zijn dus de overige tak<strong>en</strong><br />

(inclusief gat<strong>en</strong>) die teg<strong>en</strong>over elkaar staan verschill<strong>en</strong>d. Stel er is e<strong>en</strong> tijdstip t waarop in S ′ I e<strong>en</strong> taak a<br />

iets anders.<br />

staat <strong>en</strong> in S ′ J<br />

<strong>en</strong> kan a word<strong>en</strong> toegevoegd waardoor<br />

de opbr<strong>en</strong>gst in J ′ stijgt. Dit is in teg<strong>en</strong>spraak met de vooronderstelde optimaliteit <strong>van</strong> SJ.<br />

1. Als op tijdstip t = t1 e<strong>en</strong> gat in S ′ J zit, dan zit a nerg<strong>en</strong>s in S′ J<br />

2. Als a e<strong>en</strong> gat is op t = t2 <strong>en</strong> erteg<strong>en</strong>over staat e<strong>en</strong> taak b, dan is de verzameling I ∪ {b} e<strong>en</strong> uitvoerbare<br />

verzameling <strong>en</strong> heeft de gulzige algoritme ge<strong>en</strong> geldige red<strong>en</strong> om te stopp<strong>en</strong> na de vorming <strong>van</strong> I.<br />

3. De overgebelev<strong>en</strong> mogelijkheid is dat teg<strong>en</strong>over e<strong>en</strong> werkelijke taak a ′ op t = t3 e<strong>en</strong> werkelijke taak b ′<br />

staat. Dan staat a ′ niet in J <strong>en</strong> b ′ niet in I. Er zijn dan drie mogelijkhed<strong>en</strong>.<br />

(a) ga ′ > gb ′, dan kan b′ ver<strong>van</strong>g<strong>en</strong> word<strong>en</strong> door a ′ <strong>en</strong> de opbr<strong>en</strong>gst <strong>van</strong> J vergroot word<strong>en</strong>. Dit is in<br />

teg<strong>en</strong>spraak met de optimaliteit <strong>van</strong> J.<br />

(b) ga ′ < gb ′, maar dan is I − {a′ } ∪ {b ′ } uitvoerbaar <strong>en</strong> ga ′ < gb ′ dus als de gulzige algoritme a′ kiest,<br />

dan kiest zij b ′ . Teg<strong>en</strong>spraak.<br />

(c) ga ′ = gb ′.<br />

t1 t2 t3<br />

S ′ I . . . a . . . . . . a ′ . . .<br />

S ′ J . . . . . . b . . . b ′ . . .<br />

De <strong>en</strong>ige manier waarop I <strong>en</strong> J dus kunn<strong>en</strong> verschill<strong>en</strong> is als ze verschill<strong>en</strong>de tak<strong>en</strong> hebb<strong>en</strong> met dezelfde<br />

opbr<strong>en</strong>gst, maar dan zijn hun totale opbr<strong>en</strong>gst<strong>en</strong> natuurlijk ook gelijk.<br />

42


Meerdere Verwerkingse<strong>en</strong>hed<strong>en</strong><br />

Tot hier hebb<strong>en</strong> we het gehad over tak<strong>en</strong> die moet<strong>en</strong> word<strong>en</strong> uitgevoerd door één verwerkingse<strong>en</strong>heid. We<br />

kunn<strong>en</strong> ons echter e<strong>en</strong> postkantoor voorstell<strong>en</strong> waar meerdere beambt<strong>en</strong> aan e<strong>en</strong> balie staan. Iedere beambte<br />

kan in principe elke klant help<strong>en</strong>, <strong>en</strong> de klant wordt geholp<strong>en</strong> door de eerstvolg<strong>en</strong>de vrijkom<strong>en</strong>de beambte.<br />

Gebruikelijk is in dit systeem dat de klant<strong>en</strong> word<strong>en</strong> afgehandeld in volgorde <strong>van</strong> binn<strong>en</strong>komst, maar is dit<br />

ook optimaal?<br />

Ons model is e<strong>en</strong> verzameling <strong>van</strong> machines die allemaal elke taak <strong>van</strong> e<strong>en</strong> verzameling tak<strong>en</strong> uit {1, . . . , n}<br />

kunn<strong>en</strong> uitvoer<strong>en</strong>. De e<strong>en</strong>voudigste vorm <strong>van</strong> het probleem is die waarbij elke uit te voer<strong>en</strong> taak e<strong>en</strong> starttijd<br />

si <strong>en</strong> e<strong>en</strong> eindtijd ti heeft. Het optimaliseringsprobleem is het gebruik<strong>en</strong> <strong>van</strong> e<strong>en</strong> minimaal aantal machines<br />

om alle tak<strong>en</strong> uit te voer<strong>en</strong>. Het is duidelijk dat twee tak<strong>en</strong> niet op dezelfde machine kunn<strong>en</strong> word<strong>en</strong><br />

uitgevoerd, als de tijd waarin ze word<strong>en</strong> uitgevoerd overlapt. De voor de hand ligg<strong>en</strong>de strategie is dus de<br />

tak<strong>en</strong> net zolang aan e<strong>en</strong> gegev<strong>en</strong> verzameling machines toe te wijz<strong>en</strong> totdat het niet meer mogelijk is om<br />

e<strong>en</strong> nieuwe taak aan één <strong>van</strong> de machines uit de verzameling toe te wijz<strong>en</strong>. Dan schakel<strong>en</strong> we e<strong>en</strong> nieuwe<br />

machine in. Om deze algoritme geord<strong>en</strong>d uit te voer<strong>en</strong>, ord<strong>en</strong><strong>en</strong> we eerst de tak<strong>en</strong> naar starttijd <strong>en</strong> voeg<strong>en</strong><br />

de tak<strong>en</strong> in die volgorde in. Deze strategie blijkt in dit geval ook optimaal. Dit kunn<strong>en</strong> we als volgt bewijz<strong>en</strong>.<br />

Stel onze algoritme vindt voor de tak<strong>en</strong> {1, . . . , n}, waarbij de starttijd<strong>en</strong> oplop<strong>en</strong>d, dat er k machines<br />

nodig zijn. We moet<strong>en</strong> lat<strong>en</strong> zi<strong>en</strong> dat het niet met minder kan. Laat taak i de taak zijn waarvoor de k-de<br />

machine erbij is geroep<strong>en</strong>. Taak i kon niet word<strong>en</strong> uitgevoerd op machines 1, . . . , k − 1 dus moet er aan elk<br />

<strong>van</strong> deze machines e<strong>en</strong> taak toegewez<strong>en</strong> Tj zijn die e<strong>en</strong> conflict heeft met taak i. De starttijd <strong>van</strong> elke Tj<br />

moet ligg<strong>en</strong> voor si, want Tj was eerder ingedeeld <strong>en</strong> de lijst met tak<strong>en</strong> is gesorteerd. De eindtijd <strong>van</strong> elke<br />

Tj moet ligg<strong>en</strong> ná si, anders was er niet met elke machine e<strong>en</strong> conflict. We zi<strong>en</strong> dat deze k − 1 tak<strong>en</strong> niet<br />

alle<strong>en</strong> e<strong>en</strong> conflict hebb<strong>en</strong> met de i-de taak, maar ook met elkaar. Immers het tijdstip si komt in al deze<br />

tak<strong>en</strong> voor. In totaal hebb<strong>en</strong> we dus e<strong>en</strong> verzameling <strong>van</strong> k tak<strong>en</strong> die paarsgewijs e<strong>en</strong> conflict hebb<strong>en</strong>. Zo’n<br />

verzameling tak<strong>en</strong> kan niet op k − 1 machines word<strong>en</strong> uitgevoerd.<br />

Op het thema scheduling bestaan <strong>en</strong>orm veel variaties. Jobs kunn<strong>en</strong> e<strong>en</strong>heid tijd nem<strong>en</strong> of e<strong>en</strong> tijdsinterval.<br />

Er zijn situaties waarin elk <strong>van</strong> de jobs op elke machine kunn<strong>en</strong> word<strong>en</strong> uitgevoerd, <strong>en</strong> er zijn sc<strong>en</strong>ario’s<br />

waarin elke job zijn eig<strong>en</strong> soort machine heeft. E<strong>en</strong> job kan op één machine word<strong>en</strong> uitgevoerd <strong>en</strong> is dan klaar<br />

of e<strong>en</strong> job kan langs meerdere machines moet<strong>en</strong>. Het kan zo zijn dat e<strong>en</strong> job die e<strong>en</strong>maal op e<strong>en</strong> machine<br />

is gestart ook afgemaakt moet word<strong>en</strong> of e<strong>en</strong> job kan onderbrok<strong>en</strong> word<strong>en</strong> <strong>en</strong> later weer opgepakt etc. etc.<br />

Voor lang niet alle <strong>van</strong> deze problem<strong>en</strong> bestaan gulzige algoritm<strong>en</strong>. Veel <strong>van</strong> deze problem<strong>en</strong> zijn zo moeilijk<br />

dat er alle<strong>en</strong> maar expon<strong>en</strong>tiële tijd begr<strong>en</strong>sde algoritm<strong>en</strong> voor bestaan. Verder kunn<strong>en</strong> de problem<strong>en</strong> ook<br />

nog op andere manier<strong>en</strong> als optimaliseringsproblem<strong>en</strong> word<strong>en</strong> voorgesteld dan het minimaliser<strong>en</strong> <strong>van</strong> het<br />

aantal gebruikte machines. Je kunt ook bijvoorbeeld de totale overschrijding <strong>van</strong> de deadlines minimaliser<strong>en</strong><br />

of de totaal gebruikte tijd op alle machines. Kortom de variaties zijn eindeloos <strong>en</strong> dit onderwerp is e<strong>en</strong> actief<br />

onderwerp <strong>van</strong> research.<br />

2.1.6 Somm<strong>en</strong><br />

1. Laat zi<strong>en</strong> dat het systeem <strong>van</strong> euromunt<strong>en</strong> de eig<strong>en</strong>schap heeft dat de gulzige algoritme voor het<br />

teruggev<strong>en</strong> <strong>van</strong> e<strong>en</strong> bepaald bedrag altijd het minimum aantal munt<strong>en</strong> vindt. Aanwijzing. Gebruik<br />

e<strong>en</strong> Lemma dat zegt dat er voor elke muntwaarde, behalve de grootste, e<strong>en</strong> maximum aantal munt<strong>en</strong><br />

is dat in de optimale oplossing kan zitt<strong>en</strong>.<br />

2. Bed<strong>en</strong>k e<strong>en</strong> systeem <strong>van</strong> muntwaard<strong>en</strong> waarbij de gulzige algoritme uit deze sectie niet tot e<strong>en</strong> optimale<br />

oplossing leidt.<br />

3. Toon aan dat de gulzige algoritme voor knapsack waarbij eerst zoveel mogelijk <strong>van</strong> het object met de<br />

grootste waarde/gewicht ratio altijd leidt tot e<strong>en</strong> optimale oplossing.<br />

4. Laat P1, . . . , Pn e<strong>en</strong> verzameling programmas zijn die op e<strong>en</strong> schijf word<strong>en</strong> opgeslag<strong>en</strong>. Programma Pi<br />

heeft si megabyte ruimte nodig. De capaciteit <strong>van</strong> de schijf is D megabyte, waar D < � si.<br />

43


(a) Kunn<strong>en</strong> we e<strong>en</strong> gulzige algoritme gebruik<strong>en</strong> om zoveel mogelijk programma’s op de schijf op te<br />

slaan?<br />

(b) Kunn<strong>en</strong> we e<strong>en</strong> gulzige algoritme gebruik<strong>en</strong> om zoveel mogelijk megabyt<strong>en</strong> <strong>van</strong> de schijf te gebruik<strong>en</strong>?<br />

5. Gegev<strong>en</strong> zijn de lijst<strong>en</strong> L1, L2, L3 <strong>en</strong> L4 met respectievelijke l<strong>en</strong>gt<strong>en</strong> 10, 20, 30, 40.<br />

(a) Neem aan dat de kost<strong>en</strong> <strong>van</strong> het sam<strong>en</strong>voeg<strong>en</strong> <strong>van</strong> twee lijst<strong>en</strong> ev<strong>en</strong>redig is met de l<strong>en</strong>gte <strong>van</strong> de<br />

resulter<strong>en</strong>de lijst, <strong>en</strong> dat we niet meer dan twee lijst<strong>en</strong> in één keer kunn<strong>en</strong> sam<strong>en</strong>voeg<strong>en</strong>. Wat is<br />

de optimale volgorde om L1, . . . , L4 tot één lijst L sam<strong>en</strong> te voeg<strong>en</strong>?<br />

(b) Beschrijf e<strong>en</strong> greedy algoritme voor het algem<strong>en</strong>e geval: input: lijst<strong>en</strong> L1, . . . , Ln <strong>van</strong> verschill<strong>en</strong>de<br />

l<strong>en</strong>gte; output: één lijst L<br />

(c) Bewijs dat deze algoritme optimaal is; dwz. dat het gebruikte aantal bewerking<strong>en</strong> minimaal is.<br />

6. Geef e<strong>en</strong> voorbeeld <strong>van</strong> e<strong>en</strong> graaf waaruit blijkt dat bij het zoek<strong>en</strong> naar het kortste pad in de graaf het<br />

altijd kiez<strong>en</strong> <strong>van</strong> de kant met het kleinste gewicht niet tot e<strong>en</strong> optimale oplossing leidt.<br />

7. Als e<strong>en</strong> graaf negatieve kant<strong>en</strong> heeft, is het vind<strong>en</strong> <strong>van</strong> e<strong>en</strong> opspann<strong>en</strong>de verzameling <strong>van</strong> minimale<br />

kost<strong>en</strong> nog steeds zinvol. De opspann<strong>en</strong>de structuur hoeft dan niet noodzakelijk meer e<strong>en</strong> boom te<br />

zijn. Hoe kunn<strong>en</strong> we onze algoritm<strong>en</strong> aanpass<strong>en</strong> zodat ze het gew<strong>en</strong>ste resultaat oplever<strong>en</strong>?<br />

8. E<strong>en</strong> graaf hoeft niet noodzakelijke één minimale opspann<strong>en</strong>de boom te hebb<strong>en</strong>. Wanneer is dit wel het<br />

geval? Geef e<strong>en</strong> bewijs.<br />

9. E<strong>en</strong> Dijkstra boom is e<strong>en</strong> boom die bestaat uit e<strong>en</strong> punt v <strong>en</strong> verder alle kortste pad<strong>en</strong> <strong>van</strong> v naar de<br />

knop<strong>en</strong> in de graaf. (Waarom is dat e<strong>en</strong> boom?). Laat zi<strong>en</strong> dat voor e<strong>en</strong> gegev<strong>en</strong> graaf e<strong>en</strong> Dijkstra<br />

boom niet altijd e<strong>en</strong> minimale opspann<strong>en</strong>de boom is, maar dat e<strong>en</strong> Dijkstra boom wel altijd minst<strong>en</strong>s<br />

één kant geme<strong>en</strong> heeft met e<strong>en</strong> minimale opspann<strong>en</strong>de boom.<br />

10. In e<strong>en</strong> bepaald gebied bevind<strong>en</strong> zich n draadloze stations. Elk station heeft zijn eig<strong>en</strong> communicatiesnelheid.<br />

Als e<strong>en</strong> snel station met e<strong>en</strong> langzaam station praat, dan moet de snelheid <strong>van</strong> de communicatie<br />

aangepast word<strong>en</strong> aan het langzame station. M<strong>en</strong> wil e<strong>en</strong> topologie schets<strong>en</strong> waarbij <strong>van</strong>af één punt<br />

elk station kan word<strong>en</strong> bereikt (<strong>en</strong> dus elk station met minst<strong>en</strong>s één ander station praat) <strong>en</strong> waarbij<br />

de gemiddelde snelheid zo hoog mogelijk is. Bed<strong>en</strong>k e<strong>en</strong> greedy algoritme voor dit probleem. U mag<br />

hierbij het vertrag<strong>en</strong>de effect <strong>van</strong> het prat<strong>en</strong> <strong>van</strong> één station met meerdere andere verwaarloz<strong>en</strong> (<strong>en</strong><br />

dus aannem<strong>en</strong> dat e<strong>en</strong> snel station met meerdere snelhed<strong>en</strong> kan communicer<strong>en</strong>).<br />

Programmer<strong>en</strong><br />

1. E<strong>en</strong> verladingsbedrijf onderhoudt di<strong>en</strong>st<strong>en</strong> tuss<strong>en</strong> Rotterdam <strong>en</strong> Schaffhaus<strong>en</strong>, beide geleg<strong>en</strong> aan de<br />

Rijn. Het bedrijf heeft 10 schep<strong>en</strong> met verschill<strong>en</strong>de capaciteit<strong>en</strong> <strong>van</strong> twee t.e.m. ti<strong>en</strong> ton. E<strong>en</strong> schip<br />

dat twee keer zo zwaar is doet anderhalf keer zo lang over de reis. Van <strong>Amsterdam</strong> naar Shaffhaus<strong>en</strong><br />

vervoert het bedrijf tarwe, rijst <strong>en</strong> mais, <strong>en</strong> in omgekeerde richting rogge, grind <strong>en</strong> zand. De winst per<br />

100 kilo is respectievelijk 1, 3 <strong>en</strong> 4 euro voor tarwe rijst <strong>en</strong> mais, <strong>en</strong> 2, 5 <strong>en</strong> 0.5 euro rogge, grind <strong>en</strong><br />

zand, <strong>en</strong> we houd<strong>en</strong> er in de simulatie ge<strong>en</strong> rek<strong>en</strong>ing mee dat schep<strong>en</strong> moet<strong>en</strong> word<strong>en</strong> schoongemaakt<br />

voordat ze de terugweg met e<strong>en</strong> nieuwe lading kunn<strong>en</strong> aanvaard<strong>en</strong>. Experim<strong>en</strong>teer met verschill<strong>en</strong>de<br />

verladingsstrategie<strong>en</strong> (hoge winst in grote schep<strong>en</strong>, snelle schep<strong>en</strong> etc.) <strong>en</strong> berek<strong>en</strong> de winst. Tek<strong>en</strong>t<br />

er zich e<strong>en</strong> gulzige algoritme af? U hoeft hier ge<strong>en</strong> bewijz<strong>en</strong> te gev<strong>en</strong>.<br />

2.2 Verdeel <strong>en</strong> Heers<br />

Verdeel <strong>en</strong> heers is e<strong>en</strong> adagium dat teruggaat tot de oude Romein<strong>en</strong> (divide et impera). De betek<strong>en</strong>is <strong>van</strong><br />

dat adagium is tot op zekere hoogte vergelijkbaar met de betek<strong>en</strong>is die we er in de hed<strong>en</strong>daagse algoritmiek<br />

44


aan hecht<strong>en</strong>. De Romein<strong>en</strong> war<strong>en</strong> erop gericht de teg<strong>en</strong>standers uit elkaar te spel<strong>en</strong>, zodat ze met elkaar veel<br />

meer dan met de Romein<strong>en</strong> oorlog zoud<strong>en</strong> voer<strong>en</strong> waardoor de Romein<strong>en</strong> hun macht kond<strong>en</strong> handhav<strong>en</strong>. In<br />

de algoritmiek will<strong>en</strong> we e<strong>en</strong> <strong>en</strong>kel groot probleem graag uit elkaar trekk<strong>en</strong> in kleinere deelproblem<strong>en</strong> die<br />

gemakkelijk te hanter<strong>en</strong> zijn. De oplossing<strong>en</strong> voor de kleine deelproblem<strong>en</strong> sam<strong>en</strong> vorm<strong>en</strong> dan e<strong>en</strong> oplossing<br />

voor het grote probleem. Als voorbeeld gebruik<strong>en</strong> we het voorbeeld <strong>van</strong> de volledige inductie gegev<strong>en</strong> in<br />

Sectie 1.4 op pagina 26. Het probleem is het vollegg<strong>en</strong> <strong>van</strong> e<strong>en</strong> vierkant met L vormige figur<strong>en</strong>, <strong>en</strong> het<br />

probleem is simpel als het vierkant afmeting<strong>en</strong> 2 × 2 heeft. E<strong>en</strong> verdeel-<strong>en</strong>-heersalgoritme dat dit probleem<br />

oplost voor grotere vierkant<strong>en</strong> gaat (dus) als in Figuur 2.1.<br />

1: Square(n, i, j)<br />

2: if n = 2 th<strong>en</strong><br />

3: Leg de <strong>en</strong>ige L zo dat de op<strong>en</strong>ing op i,j komt.<br />

4: else<br />

5: do 4 times<br />

6: set(i ′ , j ′ );<br />

7: call Square(n/2,i’,j’);<br />

8: <strong>en</strong>d do 4 times<br />

9: put results together;<br />

10: return(result);<br />

11: <strong>en</strong>d if<br />

Figuur 2.1: Recursieve algoritme voor de L-overdekking<br />

Inductie, verdeel <strong>en</strong> heers, <strong>en</strong> recurr<strong>en</strong>te betrekking<strong>en</strong> gaan in de algoritmiek hand in hand. De inductie<br />

levert het bewijs <strong>van</strong> correctheid, de verdeel-<strong>en</strong>-heersstrategie levert de oplossing voor het probleem, <strong>en</strong> de<br />

bijbehor<strong>en</strong>de recurr<strong>en</strong>te betrekking levert de complexiteit <strong>van</strong> de algoritme. Niet altijd is het efficiënt om<br />

e<strong>en</strong> verdeel-<strong>en</strong>-heersstrategie toe te pass<strong>en</strong>, ook al ligt die voor de hand. In Hoofdstuk 1 hebb<strong>en</strong> we daar<br />

(pagina 21) al e<strong>en</strong> afschrikwekk<strong>en</strong>d voorbeeld <strong>van</strong> gezi<strong>en</strong>. Soms echter is verdeel <strong>en</strong> heers de <strong>en</strong>ige manier<br />

om e<strong>en</strong> probleem te behapp<strong>en</strong> <strong>en</strong> soms ook levert het wel degelijk e<strong>en</strong> efficiëntere algoritme dan de voor<br />

de hand ligg<strong>en</strong>de. E<strong>en</strong> beroemd geword<strong>en</strong> voorbeeld hier<strong>van</strong> is de matrixverm<strong>en</strong>igvuldigingsalgoritme <strong>van</strong><br />

V. Strass<strong>en</strong> [Str69].<br />

2.2.1 Matrixverm<strong>en</strong>igvuldiging<br />

Stel we hebb<strong>en</strong> twee n × n matrices A <strong>en</strong> B die we met elkaar will<strong>en</strong> verm<strong>en</strong>igvuldig<strong>en</strong>. De algoritme om<br />

dat te do<strong>en</strong> is dat we <strong>van</strong> matrix A steeds e<strong>en</strong> rij vector nem<strong>en</strong> <strong>en</strong> <strong>van</strong> matrix B e<strong>en</strong> kolomvector <strong>en</strong> <strong>van</strong><br />

deze twee vector<strong>en</strong> het inproduct bepal<strong>en</strong>. Zo geeft het inproduct <strong>van</strong> de ide rij <strong>van</strong> A <strong>en</strong> de jde kolom <strong>van</strong><br />

B het elem<strong>en</strong>t i, j <strong>van</strong> de productmatrix C. De complexiteit <strong>van</strong> deze algoritme is n 3 . Immers, we moet<strong>en</strong><br />

n 2 inproduct<strong>en</strong> bepal<strong>en</strong> <strong>en</strong> elk inproduct kost n verm<strong>en</strong>igvuldiging<strong>en</strong>. Er is e<strong>en</strong> andere methode, gebaseerd<br />

op het verdeel-<strong>en</strong>-heersprincipe die e<strong>en</strong> effici<strong>en</strong>tere algoritme oplevert.<br />

Wanneer we voor het gemak aannem<strong>en</strong> dat n e<strong>en</strong> 2-macht is, n = 2 k dan zi<strong>en</strong> we dat we matrix A<br />

in vier deelmatrices kunn<strong>en</strong> verdel<strong>en</strong> A1, . . . , A4 <strong>en</strong> ook matrix B in B1, . . . , B4, met de eig<strong>en</strong>schap dat<br />

we de productmatrix C ook kunn<strong>en</strong> bepal<strong>en</strong> door 8 matrixverm<strong>en</strong>ivuldiging<strong>en</strong>(zie Figuur 2.2). Immers,<br />

C1 = A1 × B1 + A2 × B3, C2 = A1 × B2 + A2 × B4, C3 = A3 × B1 + A4 × B3 <strong>en</strong> C4 = A3 × B2 + A4 × B4.<br />

Bov<strong>en</strong>di<strong>en</strong> is bij deze verm<strong>en</strong>igvuldiging de aanname <strong>van</strong> commutativiteit niet nodig, zodat ze inderdaad<br />

voor matrixverm<strong>en</strong>igvuldiging geldig is.<br />

� A1 A2<br />

A3 A4<br />

� � B1 B2<br />

B3 B4<br />

�<br />

=<br />

� C1 C2<br />

C3 C4<br />

Figuur 2.2: Onderverdeling bij matrixverm<strong>en</strong>igvuldiging<br />

45<br />


We kunn<strong>en</strong> dus in plaats <strong>van</strong> de standaardalgoritme voor matrixverm<strong>en</strong>givuldiging e<strong>en</strong> verdeel-<strong>en</strong>heersstrategie<br />

implem<strong>en</strong>ter<strong>en</strong> die steeds kleinere (vierkante) matrices met elkaar verm<strong>en</strong>igvuldigt, waarbij<br />

het triviale geval de verm<strong>en</strong>igvuldiging <strong>van</strong> één bij één matrices is. De recurr<strong>en</strong>te betrekking die bij deze<br />

algoritme hoort is T (n) = 8T (n/2). Wanneer we deze betrekking oploss<strong>en</strong> zi<strong>en</strong> we T (n) ∈ O(n 3 ) zodat de<br />

verdeel-<strong>en</strong>-heersstrategie hier wel e<strong>en</strong> andere, maar niet mete<strong>en</strong> e<strong>en</strong> betere algoritme oplevert. Het probleem<br />

zit in het aantal recursieve aanroep<strong>en</strong> <strong>van</strong> de matrixverm<strong>en</strong>igvuldigingsalgoritme dat gedaan wordt. Als we<br />

op dit aantal zoud<strong>en</strong> kunn<strong>en</strong> bezuinig<strong>en</strong>, dan zou de algoritme sneller word<strong>en</strong>. Dit is precies de observatie<br />

die V. Strass<strong>en</strong> [Str69] heeft gedaan. In plaats <strong>van</strong> met 8 kunn<strong>en</strong> we, door slim eerder verkreg<strong>en</strong> tuss<strong>en</strong>resultat<strong>en</strong><br />

te gebruik<strong>en</strong>, toe met zev<strong>en</strong> verm<strong>en</strong>igvuldiging<strong>en</strong>, waardoor de complexiteit <strong>van</strong> de algoritme daalt<br />

naar n log 7 , e<strong>en</strong> beduid<strong>en</strong>d efficiëntere algoritme.<br />

De zev<strong>en</strong> product<strong>en</strong> zijn de volg<strong>en</strong>de.<br />

1. M1 = (A3 + A4 − A1)(B3 − B2 + B1)<br />

2. M2 = A1B1<br />

3. M3 = A2B3<br />

4. M4 = (A1 − A3)(B4 − B2)<br />

5. M5 = (A3 + A4)(B2 − B1)<br />

6. M6 = (A2 − A3 + A1 − A4)B4<br />

7. M7 = A4(B1 + B4 − B2 − B3)<br />

Waarna de productmatrix wordt<br />

�<br />

C =<br />

2.2.2 Zoek<strong>en</strong> <strong>en</strong> sorter<strong>en</strong><br />

M2 + M3<br />

M1 + M2 + M5 + M6<br />

M1 + M2 + M4 − M7 M1 + M2 + M4 + M5<br />

E<strong>en</strong> zeer bek<strong>en</strong>d voorbeeld <strong>van</strong> e<strong>en</strong> probleemgebied waar de verdeel-<strong>en</strong>-heersstrategie succesvol is, is het<br />

zoek<strong>en</strong> <strong>en</strong> sorter<strong>en</strong>. In het voorwoord <strong>van</strong> “The Art of Computer Programming, Vol. 3” [Knu73] zegt Donald<br />

E. Knuth: “...Indeed, I believe that virtually every important aspect of programming arises somewhere in<br />

the context of sorting or searching!”. Het hele deel 3 is dan ook aan zoek<strong>en</strong> <strong>en</strong> sorter<strong>en</strong> gewijd. Intuss<strong>en</strong>,<br />

meer dan 30 jaar later, zijn er meer toepassing<strong>en</strong> <strong>van</strong> programmeertechniek<strong>en</strong> gekom<strong>en</strong>, maar toch is zoek<strong>en</strong><br />

<strong>en</strong> sorter<strong>en</strong> nog e<strong>en</strong> zeer belangrijk onderwerp in de informatica. Moderne ontwikkeling<strong>en</strong> als het internet<br />

hebb<strong>en</strong> zoektechniek<strong>en</strong> alle<strong>en</strong> nog maar belangrijker gemaakt. Wij zull<strong>en</strong> hier niet honderd<strong>en</strong> pagina’s aan<br />

zoek<strong>en</strong> <strong>en</strong> sorter<strong>en</strong> wijd<strong>en</strong>, maar we zull<strong>en</strong> wel in het kader <strong>van</strong> de verdeel-<strong>en</strong>-heerstechniek e<strong>en</strong> paar <strong>van</strong> de<br />

bek<strong>en</strong>dste algoritm<strong>en</strong> besprek<strong>en</strong>.<br />

zoek<strong>en</strong>: binary search<br />

We zull<strong>en</strong> steeds do<strong>en</strong> alsof de invoer voor zoek <strong>en</strong> sorteeralgoritm<strong>en</strong> bestaat uit e<strong>en</strong> rij getall<strong>en</strong>. De complexiteit<br />

<strong>van</strong> de algoritme zull<strong>en</strong> we dan uitdrukk<strong>en</strong> in het aantal getall<strong>en</strong>. De l<strong>en</strong>gte <strong>van</strong> de invoer hangt<br />

hiermee wel sam<strong>en</strong> maar is hieraan niet gelijk. Als er n getall<strong>en</strong> op de invoer staan die in m bits kunn<strong>en</strong><br />

word<strong>en</strong> uitgedrukt is de l<strong>en</strong>gte <strong>van</strong> de invoer natuurlijk nm <strong>en</strong> niet n. Toch zull<strong>en</strong> we de probleemgrootte<br />

hier voor het gemak met n aanduid<strong>en</strong>. Bij het zoek<strong>en</strong> in e<strong>en</strong> rij getall<strong>en</strong> naar e<strong>en</strong> gegev<strong>en</strong> getal maakt het<br />

e<strong>en</strong> dramatisch verschil of de gegev<strong>en</strong> rij gesorteerd is of niet. In e<strong>en</strong> ongesorteerde rij is het <strong>en</strong>ige dat we<br />

kunn<strong>en</strong> do<strong>en</strong> vooraan de rij beginn<strong>en</strong> <strong>en</strong> deze <strong>van</strong> voor naar achter onderzoek<strong>en</strong> totdat we het getal gevond<strong>en</strong><br />

hebb<strong>en</strong> of niet. Worst case kost dus het doorzoek<strong>en</strong> <strong>van</strong> n getall<strong>en</strong> θ(n). Dat deze ondergr<strong>en</strong>s geldt is te<br />

bewijz<strong>en</strong> met e<strong>en</strong> zog<strong>en</strong>oemd “adversary argum<strong>en</strong>t”. Voor elke methode die in één of andere volgorde de rij<br />

doorzoekt, is er e<strong>en</strong> rij die het gezochte getal als laatste in deze volgorde heeft staan. Voordat alle getall<strong>en</strong><br />

46<br />

�<br />

.


zijn bekek<strong>en</strong> kun je dus onmogelijk zegg<strong>en</strong> of het gezochte getal in de rij staat of niet. In het bijzonder als<br />

dat getal niet in de rij staat.<br />

De situatie wordt heel anders wanneer de rij getall<strong>en</strong> gesorteerd is. We kunn<strong>en</strong> nu gebruik mak<strong>en</strong> <strong>van</strong><br />

e<strong>en</strong> vergelijking <strong>van</strong> de getall<strong>en</strong> <strong>en</strong> bijvoorbeeld concluder<strong>en</strong> dat als e<strong>en</strong> het gezochte getal groter is dan dan<br />

e<strong>en</strong> getrokk<strong>en</strong> getal uit de gesorteerde rij, het getal ook groter zal zijn dan alle getall<strong>en</strong> die in de rij daarvoor<br />

kom<strong>en</strong>. Dus die getall<strong>en</strong> hoev<strong>en</strong> dan niet meer bekek<strong>en</strong> te word<strong>en</strong>. Deze observatie geeft aanleiding tot de<br />

zoekalgoritme die bek<strong>en</strong>d staat als binary search.<br />

1: input: e<strong>en</strong> rij getall<strong>en</strong> row[1 . . . n]; e<strong>en</strong> getal k<br />

2: min=1, max=n<br />

3: while min < max do<br />

4: middle=⌊min + max /2⌋;<br />

5: if row[middle] == k th<strong>en</strong><br />

6: return(middle);<br />

7: <strong>en</strong>d if<br />

8: if row[middle] > k th<strong>en</strong><br />

9: max=middle;<br />

10: <strong>en</strong>d if<br />

11: if row[middle] < k th<strong>en</strong><br />

12: min=middle;<br />

13: <strong>en</strong>d if<br />

14: <strong>en</strong>d while<br />

15: return(not found);<br />

De recurr<strong>en</strong>te betrekking die bij deze zoekmethode hoort is T (n) = T (n/2) + c, waaruit volgt dat de<br />

tijdcomplexiteit <strong>van</strong> deze algoritme O(log n) is.<br />

sorter<strong>en</strong>: quicksort<br />

Net als bij zoek<strong>en</strong> is de divide <strong>en</strong> conquer methode ook bij sorter<strong>en</strong> zeer in trek. E<strong>en</strong> in de praktijk<br />

veelgebruikte zoekmethode is quicksort. Deze methode heeft e<strong>en</strong> worst-case complexiteit <strong>van</strong> O(n 2 ), dus<br />

behoort de methode eig<strong>en</strong>lijk tot de “dommere” sorteeralgoritm<strong>en</strong>. Niettemin is ze zeer populair omdat ze<br />

e<strong>en</strong>voudig te implem<strong>en</strong>ter<strong>en</strong> is, <strong>en</strong> in de praktijk vrijwel altijd veel goedkoper is dan O(n 2 ). De average<br />

case complexiteit <strong>van</strong> deze sorteermethode is O(n log n), zoals we hieronder zull<strong>en</strong> zi<strong>en</strong>. Eerst besprek<strong>en</strong><br />

we de methode. Uitgangspunt is dat e<strong>en</strong> rij getall<strong>en</strong> die bestaat uit 1 elem<strong>en</strong>t gesorteerd is. E<strong>en</strong> rij <strong>van</strong> n<br />

getall<strong>en</strong> kunn<strong>en</strong> we in twee rij<strong>en</strong> verdel<strong>en</strong> door e<strong>en</strong> elem<strong>en</strong>t uit de rij te kiez<strong>en</strong>, vervolg<strong>en</strong>s alles dat kleiner<br />

dan dat elem<strong>en</strong>t is in de eerste rij op te slaan <strong>en</strong> alles dat groter dan of gelijk is aan dat elem<strong>en</strong>t in de tweede<br />

rij op te slaan. Als we vervolg<strong>en</strong>s de aldus geconstrueerde rij<strong>en</strong> sorter<strong>en</strong> <strong>en</strong> aan elkaar plakk<strong>en</strong>, dan is de<br />

hele rij gesorteerd. Het elem<strong>en</strong>t dat we kiez<strong>en</strong> om de twee deelrij<strong>en</strong> te mak<strong>en</strong> zull<strong>en</strong> we de as noem<strong>en</strong>. In<br />

algoritmische vorm:<br />

1: function Sort( row[1, . . . , n])<br />

2: if n > 1 th<strong>en</strong><br />

3: Choose 1 ≤ k < n;<br />

4: row1={row[i] : row[i] < row[k]};<br />

5: row2={row[i] : row[i] ≥ row[k] ∧ i �= k};<br />

6: Sort(row1);<br />

7: Sort(row2);<br />

8: return(concat<strong>en</strong>ate(row1,row[k],row2);<br />

9: else return(row);<br />

10: <strong>en</strong>d if<br />

De kost<strong>en</strong> <strong>van</strong> deze algoritme zijn zeer afhankelijk <strong>van</strong> e<strong>en</strong> goede keuze <strong>van</strong> de as, row[k]. We zi<strong>en</strong> dat<br />

het mogelijk is deze telk<strong>en</strong>s zo ongelukkig te kiez<strong>en</strong> dat de bov<strong>en</strong>gr<strong>en</strong>s op de complexiteit kwadratisch wordt.<br />

Als de as telk<strong>en</strong>s zo gekoz<strong>en</strong> wordt, dat alle overige elem<strong>en</strong>t<strong>en</strong> ofwel in row1 ofwel in row2 terchtkom<strong>en</strong>, dan<br />

is T (n) = T (n − 1) + n − 1 <strong>en</strong> deze recurr<strong>en</strong>te betrekking heeft de afschatting T (n) = θ(n 2 ). Alle<strong>en</strong> als de<br />

47


eide rij<strong>en</strong> e<strong>en</strong> constante fractie <strong>van</strong> de oorspronkelijke rij zijn, dan wordt e<strong>en</strong> betere gr<strong>en</strong>s bereikt. Immers<br />

T (n) = T (n/c) + T (n − n/c) + O(n) heeft e<strong>en</strong> O(n log n) afschatting. We zull<strong>en</strong> bewijz<strong>en</strong> dat dit in het<br />

gemiddelde geval, bij e<strong>en</strong> uniforme distributie over alle mogelijke ongesorteerde (<strong>en</strong> e<strong>en</strong> gesorteerde) rij<strong>en</strong><br />

geldt.<br />

Er zijn n! mogelijke volgord<strong>en</strong> waarin de getall<strong>en</strong> (lat<strong>en</strong> we voor het gemak 1, . . . , n aannem<strong>en</strong>) kunn<strong>en</strong><br />

staan. Laat Ri de rij in volgorde i voor i ≤ n! zijn, T (Ri) is dan de tijd die het kost om Ri met quiksort<br />

�n! i=1 T (Ri)<br />

n!<br />

te sorter<strong>en</strong>. De gemiddelde tijd T is dan . Als bek<strong>en</strong>d is op welke plaats de as in Ri thuishoort,<br />

kunn<strong>en</strong> we de kost<strong>en</strong> <strong>van</strong> het sorter<strong>en</strong> <strong>van</strong> Ri bepal<strong>en</strong>. Dat is namelijk T (Ri1) + T (Ri2) + n − 1. Als<br />

Ri uniform verdeeld is, dan is elke plaats voor de as in de gesorteerde rij ev<strong>en</strong> waarschijnlijk, <strong>en</strong> is dus<br />

T (Ri) = �n j=0 T (Ri[1, . . . j − 1]) + T (Ri[j + 1, . . . n]) + n − 1. Merk op dat het geval dat de hele rij recursief<br />

wordt doorgegev<strong>en</strong> in de procedure hier ook wordt meeg<strong>en</strong>om<strong>en</strong>. Aangezi<strong>en</strong> Ri uniform verdeeld is, zijn de<br />

beide deelrij<strong>en</strong> ook uniform verdeeld, dat will zegg<strong>en</strong> voor elke plaats i heeft elk elem<strong>en</strong>t dezelfde � kans om op<br />

i=1 T (i−1)+T (n−i)<br />

plaats i te staan. We kunn<strong>en</strong> dus voor e<strong>en</strong> willekeurige rij Ri ook stell<strong>en</strong> T (n) = n − 1 +<br />

n .<br />

Nu merk<strong>en</strong> we op dat �n i=1 T (i − 1) = �n i=1 T (n − i).<br />

We herschrijv<strong>en</strong> de uitdrukking voor T (n) tot:<br />

met T (0) = T (1) = 0.<br />

Verm<strong>en</strong>igvuldig<strong>en</strong> met n levert<br />

Dus ook dat<br />

�<br />

n�<br />

�<br />

T (n) = n − 1 + 2/n T (i − 1) ,<br />

nT (n) = n(n − 1) + 2<br />

i=1<br />

n�<br />

T (i − 1).<br />

i=1<br />

n−1 �<br />

(n − 1)T (n − 1) = (n − 1)(n − 2) + 2 T (i − 1).<br />

Trekk<strong>en</strong> we deze twee <strong>van</strong> elkaar af, dan zi<strong>en</strong> we dat<br />

Ofwel<br />

nT (n) − (n − 1)T (n − 1) = n(n − 1) − (n − 1)(n − 2) + 2T (n − 1)<br />

Substitueer T (n) = (n + 1)yn <strong>en</strong> we krijg<strong>en</strong><br />

Uitroll<strong>en</strong> <strong>van</strong> deze recurr<strong>en</strong>tie geeft<br />

i=1<br />

T (n) = (1 + 1<br />

2<br />

)T (n − 1) + (2 −<br />

n n )<br />

yn = yn−1 +<br />

yn = 2 � n<br />

j=1<br />

= 2 � n<br />

j=1<br />

2(n − 1)<br />

n(n + 1)<br />

{ 2<br />

= 2 � n<br />

j=1 1<br />

j<br />

j−1<br />

j(j+1)<br />

j+1<br />

− 1<br />

j }<br />

− 4n<br />

n+1<br />

Dus is T (n) = 2(n + 1) �n j=1 1<br />

j − 4n, waaruit volgt dat T (n) ∈ O(n log n).<br />

48


sorter<strong>en</strong>: mergesort<br />

De toepassing <strong>van</strong> verdeel <strong>en</strong> heers die we als laatste voorbeeld besprek<strong>en</strong> heeft e<strong>en</strong> O(n log n) bov<strong>en</strong>gr<strong>en</strong>s,<br />

<strong>en</strong> kan dus, gegev<strong>en</strong> de volg<strong>en</strong>de sectie word<strong>en</strong> geklassificeerd als de meest efficiënte sorteermethode. Dat<br />

deze methode in de praktijk toch niet het meest wordt toegepast is geleg<strong>en</strong> in het feit dat quicksort toch in<br />

de meeste gevall<strong>en</strong> e<strong>en</strong> O(n log n) performance haalt <strong>en</strong> bov<strong>en</strong>di<strong>en</strong> zeer e<strong>en</strong>voudig te implem<strong>en</strong>ter<strong>en</strong> is. De<br />

gedachte achter mergesort is weer dat e<strong>en</strong> rij die bestaat uit één elem<strong>en</strong>t al gesorteerd is, <strong>en</strong> dat bov<strong>en</strong>di<strong>en</strong><br />

twee gesorteerde rij<strong>en</strong> <strong>van</strong> gelijke l<strong>en</strong>gte kunn<strong>en</strong> word<strong>en</strong> sam<strong>en</strong>gevoegd tot één gesorteerde rij <strong>van</strong> de dubbele<br />

l<strong>en</strong>gte door steeds het kleinste elem<strong>en</strong>t <strong>van</strong> de twee rij<strong>en</strong> eruit te hal<strong>en</strong> <strong>en</strong> op te slaan. Aangezi<strong>en</strong> de twee<br />

rij<strong>en</strong> gesorteerd zijn, kan het kleinste elem<strong>en</strong>t in O(1) tijd gevond<strong>en</strong> word<strong>en</strong> <strong>en</strong> dus kunn<strong>en</strong> de rij<strong>en</strong> tot<br />

één rij word<strong>en</strong> sam<strong>en</strong>gevoegd in O(n) tijd. De sorteeralgoritme bestaat dan uit het herhaaldelijk in twee<br />

gelijke (of bijna gelijke) del<strong>en</strong> splits<strong>en</strong> <strong>van</strong> e<strong>en</strong> rij, de twee verkreg<strong>en</strong> deelrij<strong>en</strong> op dezelfde manier sorter<strong>en</strong>,<br />

<strong>en</strong> vervolg<strong>en</strong>s de twee gesorteerde rij<strong>en</strong> sam<strong>en</strong> te voeg<strong>en</strong>. In pseudotaal:<br />

1: Sort(row[1,. . . ,n])<br />

2: if n > 2 th<strong>en</strong><br />

3: row1=row[1, . . . , ⌊n/2⌋];<br />

4: row2=row[⌊n/2⌋ + 1, . . . , n];<br />

5: row1=Sort(row1);<br />

6: row2=Sort(row2);<br />

7: return(Merge(row1,row2);<br />

8: else<br />

9: return(row);<br />

10: <strong>en</strong>d if<br />

De routine Merge wordt dan als volgt.<br />

1: Merge(row1[1, . . . , n], row2[1, . . . , m])<br />

2: while notempty(row1) and notempty(row2) do<br />

3: pick the minimal elem<strong>en</strong>t from row1 and row2;<br />

4: add it to row;<br />

5: <strong>en</strong>d while<br />

6: return(row);<br />

Voor het sorter<strong>en</strong> <strong>van</strong> e<strong>en</strong> rij <strong>van</strong> l<strong>en</strong>gte n wordt dus twee keer de routine Sort op rij<strong>en</strong> <strong>van</strong> l<strong>en</strong>gte<br />

ongeveer n/2 aangeroep<strong>en</strong> <strong>en</strong> één keer de routine Merge op twee rij<strong>en</strong> <strong>van</strong> l<strong>en</strong>gte ongeveer n/2. De recurr<strong>en</strong>te<br />

betrekking die hierbij hoort is T (n) = 2T (n/2) + O(n), waaruit e<strong>en</strong> O(n log n) worst case bov<strong>en</strong>gr<strong>en</strong>s volgt.<br />

sorter<strong>en</strong>: Ω(n log n) ondergr<strong>en</strong>s<br />

Het sorter<strong>en</strong> volg<strong>en</strong>s MergeSort levert e<strong>en</strong> worst case bov<strong>en</strong>gr<strong>en</strong>s die gelijk is aan de ondergr<strong>en</strong>s die geldt<br />

voor sorter<strong>en</strong> in het algeme<strong>en</strong>, als dat sorter<strong>en</strong> t<strong>en</strong>minste gebaseerd is op vergelijk<strong>en</strong> <strong>van</strong> twee elem<strong>en</strong>t<strong>en</strong> uit<br />

de te sorter<strong>en</strong> rij. Er zijn nog effici<strong>en</strong>tere method<strong>en</strong> d<strong>en</strong>kbaar, bv. radix sort 1 , maar deze sorteermethod<strong>en</strong><br />

zijn doorgaans op andere principes gestoeld dan de vergelijking <strong>van</strong> twee elem<strong>en</strong>t<strong>en</strong> in de rij.<br />

Voor sorteermethod<strong>en</strong> die gebaseerd zijn op vergelijk<strong>en</strong> <strong>en</strong> verplaats<strong>en</strong> <strong>van</strong> elem<strong>en</strong>t<strong>en</strong> is Ω(n log n) e<strong>en</strong><br />

ondergr<strong>en</strong>s. We kunn<strong>en</strong> dit als volgt inzi<strong>en</strong>. Beschouw de te sorter<strong>en</strong> rij als e<strong>en</strong> rij getall<strong>en</strong> die in e<strong>en</strong><br />

boomstructuur gevoerd wordt, waarbij elke rij langs e<strong>en</strong> pad naar b<strong>en</strong>ed<strong>en</strong> loopt. In elke knoop langs het<br />

pad wordt op e<strong>en</strong> rij e<strong>en</strong> operatie (vergelijking, verplaatsing) uitgevoerd, waardoor uiteindelijk in het blad<br />

hor<strong>en</strong>de bij het gevolgde pad de gesorteerde rij staat. Twee verschill<strong>en</strong>de rij<strong>en</strong> moet<strong>en</strong> e<strong>en</strong> verschill<strong>en</strong>d<br />

pad volg<strong>en</strong>. Immers als op twee verschill<strong>en</strong>de rij<strong>en</strong> verschill<strong>en</strong>de operaties uitgevoerd word<strong>en</strong>, kunn<strong>en</strong> ze<br />

1 Bij radix sort wordt er net zoveel geheug<strong>en</strong> gereserveerd als de grootte <strong>van</strong> het maximale elem<strong>en</strong>t in de rij. Vervolg<strong>en</strong>s wordt<br />

voor ieder elem<strong>en</strong>t dat wordt aangetroff<strong>en</strong> in de rij e<strong>en</strong> boolese waarde in het bijbehor<strong>en</strong>de geheug<strong>en</strong> op true gezet, <strong>en</strong> vervolg<strong>en</strong>s<br />

wordt het hele array nagelop<strong>en</strong> <strong>en</strong> wordt het adres <strong>van</strong> de elem<strong>en</strong>t<strong>en</strong> die op true staan in e<strong>en</strong> gesorteerde rij geconcat<strong>en</strong>eerd.<br />

Soms is deze methode effici<strong>en</strong>t. Immers de complexiteit is lineair in de waarde <strong>van</strong> het grootste elem<strong>en</strong>t, <strong>en</strong> bov<strong>en</strong>di<strong>en</strong> is het<br />

geheug<strong>en</strong>gebruik ook lineair in de waarde <strong>van</strong> dit getal. Als die waarde vergelijkbaar is met het aantal elem<strong>en</strong>t<strong>en</strong> in de rij,<br />

dan hebb<strong>en</strong> we dus e<strong>en</strong> lineaire sorteermethode. Echter, aangezi<strong>en</strong> e<strong>en</strong> getal n met log n bits te repres<strong>en</strong>ter<strong>en</strong> is, kan deze<br />

sorteermethode ook expon<strong>en</strong>tieel zijn.<br />

49


niet allebei door dezelfde serie operaties (verandering <strong>van</strong> de volgorde) gesorteerd word<strong>en</strong>. Aangezi<strong>en</strong> er n!<br />

volgord<strong>en</strong> zijn, moet de boom dus n! blader<strong>en</strong> hebb<strong>en</strong>. Di<strong>en</strong>t<strong>en</strong>gevolge is er e<strong>en</strong> pad in de boom <strong>van</strong> l<strong>en</strong>gte<br />

Ω(log n!) = Ω(n log n).<br />

2.2.3 Somm<strong>en</strong><br />

1. Laat T [1..n] e<strong>en</strong> gesorteerd array <strong>van</strong> verschill<strong>en</strong>de integers zijn, die positief of negatief mog<strong>en</strong> zijn.<br />

Geef e<strong>en</strong> O(log n) algoritme die e<strong>en</strong> index i vindt met T [i] = i, als zo’n index bestaat.<br />

2. Stel er zijn drie algoritm<strong>en</strong> om hetzelfde probleem aan te pakk<strong>en</strong>.<br />

• Algoritme A lost het probleem op door het in vijf deelproblem<strong>en</strong> te verdel<strong>en</strong>, die recursief op te<br />

loss<strong>en</strong> <strong>en</strong> de oplossing<strong>en</strong> in lineaire tijd te combiner<strong>en</strong>.<br />

• Algoritme B lost problem<strong>en</strong> <strong>van</strong> grootte n op door twee deelproblem<strong>en</strong> <strong>van</strong> grootte n − 1 op te<br />

loss<strong>en</strong> <strong>en</strong> vervolg<strong>en</strong>s de oplossing<strong>en</strong> in constante tijd te combiner<strong>en</strong>.<br />

• Algoritme C lost problem<strong>en</strong> <strong>van</strong> grootte n op door ze in neg<strong>en</strong> deelproblem<strong>en</strong> <strong>van</strong> groote n/3 te<br />

verdel<strong>en</strong>, die recursief op te loss<strong>en</strong> <strong>en</strong> dan de oplossing<strong>en</strong> in O(n 2 ) tijd te combiner<strong>en</strong>.<br />

Welke algoritme kiest je <strong>en</strong> waarom?<br />

3. E<strong>en</strong> staafdiagram wordt door e<strong>en</strong> programma geproduceerd op e<strong>en</strong> n×n vierkant. Bed<strong>en</strong>k e<strong>en</strong> algoritme<br />

die de langste staaf in het diagram vindt in O(n) (dus niet O(n 2 )) tijd.<br />

4. E<strong>en</strong> onverlaat heeft de potjes babyvoeding in e<strong>en</strong> supermarkt geïnfecteerd. Er wordt beslot<strong>en</strong> het<br />

geïnfecteerde potje te vind<strong>en</strong> door proefdier<strong>en</strong> in te zett<strong>en</strong>. De incubatietijd <strong>van</strong> het virus is 48 uur.<br />

De dier<strong>en</strong>bescherming ziet de noodzaak <strong>van</strong> het zo snel mogelijk id<strong>en</strong>tificer<strong>en</strong> <strong>van</strong> het besmette potje<br />

<strong>en</strong> het onderzoek op vingerafdrukk<strong>en</strong> wel in, maar eist toch dat er niet meer dan O(log n) proefdier<strong>en</strong><br />

per n potjes word<strong>en</strong> gebruikt. Kan het besmette potje binn<strong>en</strong> 50 uur gevond<strong>en</strong> word<strong>en</strong>?<br />

5. E<strong>en</strong> spel <strong>van</strong> n kaart<strong>en</strong> bevat verschill<strong>en</strong>de afbeelding<strong>en</strong>. Het spel heeft e<strong>en</strong> grote deelverzameling als<br />

n/2 of meer kaart<strong>en</strong> dezelfde afbeelding hebb<strong>en</strong>. Geef e<strong>en</strong> O(n log n) algoritme die bepaalt of het spel<br />

e<strong>en</strong> grote deelverzameling heeft.<br />

Programmer<strong>en</strong><br />

1. Pluk e<strong>en</strong> paar flinke tekst<strong>en</strong> <strong>van</strong> het web <strong>en</strong> vergelijk de verschill<strong>en</strong>de sorteeralgoritm<strong>en</strong>, mergesort,<br />

quicksort <strong>en</strong> insertion sort.<br />

2. Matrixverm<strong>en</strong>igvuldiging kan gebruikt word<strong>en</strong> om de transitieve afsluiting <strong>van</strong> e<strong>en</strong> graaf te berek<strong>en</strong><strong>en</strong>.<br />

Maak e<strong>en</strong> random graaf op 25 knop<strong>en</strong> <strong>en</strong> berek<strong>en</strong> de transitieve afsluiting <strong>van</strong> de graaf. Doe dat op<br />

twee manier<strong>en</strong>: de standaardverm<strong>en</strong>igvuldiging <strong>en</strong> Strass<strong>en</strong>’s methode. Vergelijk de tijd<strong>en</strong>.<br />

2.3 Dynamisch Programmer<strong>en</strong><br />

E<strong>en</strong> belangrijke techniek in de optimalisatie is de techniek <strong>van</strong> het dynamisch programmer<strong>en</strong>. Het is in<br />

teg<strong>en</strong>stellng tot de top down aanpak <strong>van</strong> de verdeel-<strong>en</strong>-heersstrategieën e<strong>en</strong> bottom up aanpak die probeert<br />

optimale oplossing<strong>en</strong> voor deelproblem<strong>en</strong> te vind<strong>en</strong>. Deze word<strong>en</strong> vervolg<strong>en</strong>s sam<strong>en</strong>gesteld tot e<strong>en</strong> optimale<br />

oplossing voor het hele probleem. E<strong>en</strong> beetje zoals e<strong>en</strong> legpuzzel wordt opgelost. Telk<strong>en</strong>s wordt e<strong>en</strong> stukje<br />

<strong>van</strong> de legpuzzel opgelost. Als de stukk<strong>en</strong> grotere herk<strong>en</strong>bare verband<strong>en</strong> gaan vorm<strong>en</strong> word<strong>en</strong> ze in elkaar<br />

gepast. In 1 zag<strong>en</strong> we al, bij het berek<strong>en</strong><strong>en</strong> <strong>van</strong> Fibonaccigetall<strong>en</strong> dat het opslaan <strong>van</strong> tuss<strong>en</strong>resultat<strong>en</strong><br />

soms tot dramatische verbering kan leid<strong>en</strong>. Het berek<strong>en</strong><strong>en</strong> <strong>van</strong> Fibonaccigetall<strong>en</strong> is echter ge<strong>en</strong> optimalizeringsprobleem.<br />

Daarom is dit niet e<strong>en</strong> typisch voorbeeld voor de aanpak <strong>van</strong> e<strong>en</strong> probleem met dynamisch<br />

programmer<strong>en</strong>. E<strong>en</strong> ander probleem dat we eerder hebb<strong>en</strong> gezi<strong>en</strong>, dat <strong>van</strong> het gev<strong>en</strong> <strong>van</strong> wisselgeld kan wel<br />

word<strong>en</strong> aangepakt met dynamisch programmer<strong>en</strong>. Dat zull<strong>en</strong> we hier eerst uitwerk<strong>en</strong>. In Som 2 op pagina 43<br />

50


hebb<strong>en</strong> we gezi<strong>en</strong> dat niet in elk systeem de gulzige algoritme voor geldteruggave tot e<strong>en</strong> optimale oplossing<br />

leidt. De hieronder beschrev<strong>en</strong> aanpak met dynamisch programmer<strong>en</strong> doet dat wel.<br />

Stel we hebb<strong>en</strong> e<strong>en</strong> muntsysteem dat munt<strong>en</strong> <strong>van</strong> de waard<strong>en</strong> w1, . . . , wn heeft, <strong>en</strong> we moet<strong>en</strong> e<strong>en</strong> bedrag<br />

B teruggev<strong>en</strong>. We nem<strong>en</strong> ev<strong>en</strong> aan dat de w1 de e<strong>en</strong>heid in het muntsysteem is <strong>en</strong> dat B dus in ieder<br />

geval altijd bereikt kan word<strong>en</strong>. Nu vind<strong>en</strong> we e<strong>en</strong> optimale oplossing als volgt. Stel dat we e<strong>en</strong> optimale<br />

oplossing wet<strong>en</strong> die bestaat uit muntwaard<strong>en</strong> alle<strong>en</strong> uit w1, . . . , wi, dan kunn<strong>en</strong> we e<strong>en</strong> optimale oplossing<br />

met muntwaard<strong>en</strong> uit w2, . . . , wi+1 berek<strong>en</strong> door te observer<strong>en</strong> dat we de altijd de keuze hebb<strong>en</strong> wel of ge<strong>en</strong><br />

munt<strong>en</strong> <strong>van</strong> waarde wi+1 te gebruik<strong>en</strong>. Als we ge<strong>en</strong> muntwaarde <strong>van</strong> type wi+1 gebruik<strong>en</strong>, dan is de optimale<br />

waarde dezelfde als die we hadd<strong>en</strong> berek<strong>en</strong>d bij teruggave met alle<strong>en</strong> waard<strong>en</strong> uit w1, . . . , wi. Als we wel<br />

munt<strong>en</strong> <strong>van</strong> type wi+1 gebruik<strong>en</strong>, dan kunn<strong>en</strong> we hoogst<strong>en</strong>s W = B/wi+1 <strong>van</strong> deze munt<strong>en</strong> gebruik<strong>en</strong>, <strong>en</strong><br />

e<strong>en</strong> optimale waarde vind<strong>en</strong> we dus door voor j ≤ W te berek<strong>en</strong><strong>en</strong> wat het optimale aantal munt<strong>en</strong> voor het<br />

bedrag B−j×wi+1 is plus j. Dus Opt(B, i+1) = min{Opt(B, i)} � {Opt(B−j×wi+1, j)+j : j ≤ ⌊B/wi+1⌋}<br />

Waarbij natuurlijk Opt(B, 1) gelijk aan B is voor alle B. We kunn<strong>en</strong> ons e<strong>en</strong> tabel voorstell<strong>en</strong> waarbij<br />

we de volg<strong>en</strong>de regel (met muntwaard<strong>en</strong> wi+1 sam<strong>en</strong>stell<strong>en</strong> uit door e<strong>en</strong> aantal ker<strong>en</strong> wi in de vorige regel<br />

terug te kijk<strong>en</strong> <strong>en</strong> dan te zi<strong>en</strong> of we e<strong>en</strong> kleiner getal kunn<strong>en</strong> krijg<strong>en</strong>. Misschi<strong>en</strong> is e<strong>en</strong> getall<strong>en</strong>voorbeeld hier<br />

illustratief.<br />

Voorbeeld 2.3.1: Neem e<strong>en</strong> muntsysteem met waard<strong>en</strong> 1,4,5, <strong>en</strong> 7 <strong>en</strong> laat 9 het terug te gev<strong>en</strong> bedrag zijn.<br />

We krijg<strong>en</strong> dan:<br />

0 1 2 3 4 5 6 7 8 9<br />

1 0 1 2 3 4 5 6 7 8 9<br />

4 0 1 2 3 1 2 3 4 2 3<br />

5 0 1 2 3 1 1 2 3 2 2<br />

7 0 1 2 3 1 1 2 1 2 2<br />

Merk overig<strong>en</strong>s op dat de greedy algoritme het bedrag 9 zou vorm<strong>en</strong> uit 7, 1, <strong>en</strong> 1. ✷<br />

Het hier beschrev<strong>en</strong> patroon is e<strong>en</strong> g<strong>en</strong>eriek patroon voor algoritm<strong>en</strong> met dynamisch programmer<strong>en</strong>. Het<br />

is alle<strong>en</strong> de dim<strong>en</strong>sie <strong>van</strong> de tabel <strong>en</strong> de manier waarop deze wordt ingevuld (rijgewijs, kolomsgewijs, of langs<br />

de diagonal<strong>en</strong>) die verschilt. We bekijk<strong>en</strong> nog e<strong>en</strong> bek<strong>en</strong>de.<br />

2.3.1 Dynamisch programmer<strong>en</strong> <strong>en</strong> Knapsack<br />

Het knapsackprobleem kond<strong>en</strong> we met e<strong>en</strong> gulzige algoritme oploss<strong>en</strong> gegev<strong>en</strong> dat de object<strong>en</strong> op elke manier<br />

gedeeld kunn<strong>en</strong> word<strong>en</strong>. Dat is natuurlijk waar voor koffie <strong>en</strong> brood, maar is minder waar voor bijvoorbeeld<br />

kristall<strong>en</strong> kroonluchters. Het knapsackprobleem wordt beduid<strong>en</strong>d moeilijker als de keuze beperkt wordt tot<br />

het wel of niet me<strong>en</strong>em<strong>en</strong> <strong>van</strong> object<strong>en</strong>. Deze variant wordt ook wel de 0-1 variant <strong>van</strong> knapsack g<strong>en</strong>oemd.<br />

We kunn<strong>en</strong> 0-1 knapsack oploss<strong>en</strong> met dynamisch programmer<strong>en</strong> als volgt. Bij elk voorwerp kunn<strong>en</strong> we<br />

de beslissing nem<strong>en</strong> het voorwerp wel of niet mee te nem<strong>en</strong>. Stel dat we wet<strong>en</strong> wat de optimale oplossing<br />

is voor het probleem als we het probleem <strong>van</strong> het wel of niet me<strong>en</strong>em<strong>en</strong> <strong>van</strong> de voorwerp<strong>en</strong> beperk<strong>en</strong> tot<br />

de eerste i voorwerp<strong>en</strong> voor alle getall<strong>en</strong> tuss<strong>en</strong> 0 <strong>en</strong> b. Als we bij het i + 1e voorwerp zijn aangekom<strong>en</strong>,<br />

dan kunn<strong>en</strong> we dit voorwerp niet me<strong>en</strong>em<strong>en</strong> (dus blijft de optimale oplossing voor b geldig voor de eerste<br />

i voorwerp<strong>en</strong>) of het voorwerp wel me<strong>en</strong>em<strong>en</strong>, in welk geval we nog b − wi+1 te bested<strong>en</strong> hebb<strong>en</strong> aan de<br />

eerste i voorwerp<strong>en</strong>. Onze beslissing hangt nu alle<strong>en</strong> maar af <strong>van</strong> de vraag of Opt({1, . . . , i}, b) groter of<br />

kleiner is dan Opt({1, . . . , i}, b − wi+1) + wi+1. Zo kunn<strong>en</strong> we onze oplossingsverzameling uitbreid<strong>en</strong> tot we<br />

alle voorwerp<strong>en</strong> hebb<strong>en</strong> opg<strong>en</strong>om<strong>en</strong>, <strong>en</strong> Opt({1, . . . , n}, b) vertelt ons welke oplossing optimaal is voor de<br />

verzameling <strong>van</strong> alle voorwerp<strong>en</strong> <strong>en</strong> b. We kunn<strong>en</strong> dit in e<strong>en</strong> tabelvorm opschrijv<strong>en</strong>, waarbij we langs de<br />

horizontale as de voorwerp<strong>en</strong> uitzett<strong>en</strong> <strong>en</strong> langs de verticale as de gewicht<strong>en</strong>. Wellicht laat zich dit illustrer<strong>en</strong><br />

aan de hand <strong>van</strong> e<strong>en</strong> voorbeeld. Om het probleem wat te vere<strong>en</strong>voudig<strong>en</strong> stell<strong>en</strong> we de waarde <strong>van</strong> e<strong>en</strong> object<br />

gelijk aan het gewicht er<strong>van</strong>.<br />

Voorbeeld 2.3.2:<br />

51


1 2 3 4 5 6 b = 7<br />

w1 = 3 0 0 3 3 3 3 3<br />

w2 = 2 0 2 3 3 5 5 5<br />

w3 = 5 0 2 3 3 5 5 7<br />

w4 = 4 0 2 3 4 5 5 7<br />

w5 = 6 0 2 3 4 5 6 7<br />

Als de waarde in e<strong>en</strong> kolom <strong>van</strong> rij i naar rij i + 1 verandert, betek<strong>en</strong>t dat dat het gunstiger is het nieuw<br />

toegelat<strong>en</strong> object wel mee te nem<strong>en</strong>. ✷<br />

2.3.2 Tekstwijzig<strong>en</strong><br />

E<strong>en</strong> tekstverwerker zoekt (e<strong>en</strong> groot gedeelte <strong>van</strong> de tijd) naar e<strong>en</strong> patroon in e<strong>en</strong> tekst. E<strong>en</strong> tekst is hierbij<br />

e<strong>en</strong> lange rij tek<strong>en</strong>s, <strong>en</strong> e<strong>en</strong> patroon is e<strong>en</strong> woord of e<strong>en</strong> gedeelte <strong>van</strong> e<strong>en</strong> zin (korte rij tek<strong>en</strong>s). De matching<br />

hoeft hierbij niet volledig te zijn. Er kunn<strong>en</strong>, zowel in het patroon als de tekst letters zijn weggelat<strong>en</strong>, of<br />

veranderd.<br />

Meer precies: we zoek<strong>en</strong> e<strong>en</strong> patroon P in e<strong>en</strong> text T over hetzelfde alfabet. De edit afstand tuss<strong>en</strong> P<br />

<strong>en</strong> T is het kleinste aantal verandering<strong>en</strong> dat moet word<strong>en</strong> aangebracht om e<strong>en</strong> deelrij <strong>van</strong> tek<strong>en</strong>s <strong>van</strong> T te<br />

verander<strong>en</strong> in P . De verandering<strong>en</strong> kunn<strong>en</strong> zijn:<br />

1. Substitutie - twee overe<strong>en</strong>komstige letters kunn<strong>en</strong> verschill<strong>en</strong>, bijvoorbeeld ligg<strong>en</strong> → legg<strong>en</strong>.<br />

2. Invoeging - We kunn<strong>en</strong> e<strong>en</strong> letter aan T toevoeg<strong>en</strong> die in P voorkomt, bijvoorbeeld gat → gaat.<br />

3. Weglating - We kunn<strong>en</strong> e<strong>en</strong> letter uit T weglat<strong>en</strong> die niet in P voorkomt, bijvoorbeeld plop → pop.<br />

Er zijn natuurlijk legio andere operaties op P d<strong>en</strong>kbaar die e<strong>en</strong> deelstring <strong>van</strong> T kunn<strong>en</strong> oplever<strong>en</strong>—d<strong>en</strong>k<br />

bijvoorbeeld aan verwisseling <strong>van</strong> letters—maar deze operaties vorm<strong>en</strong> e<strong>en</strong> basis voor andere operaties. Dat<br />

wil zegg<strong>en</strong>, andere operaties die <strong>van</strong> P e<strong>en</strong> deelstring <strong>van</strong> T mak<strong>en</strong> zijn kunn<strong>en</strong> uit deze drie operaties word<strong>en</strong><br />

sam<strong>en</strong>gesteld (in feite zelfs uit de laatste twee).<br />

Lat<strong>en</strong> we prober<strong>en</strong> dit probleem met dynamisch programmer<strong>en</strong> op te loss<strong>en</strong>. We hebb<strong>en</strong> dan één of<br />

andere functie nodig die geoptimaliseerd di<strong>en</strong>t te word<strong>en</strong>. Natuurlijk is het aantal verschill<strong>en</strong> tuss<strong>en</strong> het<br />

patroon <strong>en</strong> <strong>en</strong>ige deelstring <strong>van</strong> T e<strong>en</strong> duidelijke kandidaat. P moet op <strong>en</strong>ige plaats langs T gelegd word<strong>en</strong>,<br />

<strong>en</strong> we vergelijk<strong>en</strong> de letters <strong>van</strong> P , P1,. . . ,Pn, met e<strong>en</strong> aantal letters <strong>van</strong> T —dit aantal kan zowel groter als<br />

kleiner zijn dan n. Lat<strong>en</strong> we het minimaal aantal verschill<strong>en</strong> tuss<strong>en</strong> P1 . . . Pi <strong>en</strong> e<strong>en</strong> deelstring <strong>van</strong> T die<br />

eindigt in j bijhoud<strong>en</strong> in e<strong>en</strong> array D[i, j]. Stel dat we al e<strong>en</strong> gedeelte <strong>van</strong> P , zeg P1 . . . Pi hebb<strong>en</strong> gepast op<br />

e<strong>en</strong> deelstring <strong>van</strong> T <strong>en</strong> dat we bij Tj zijn aangekom<strong>en</strong>. Hoe breid<strong>en</strong> we nu het pass<strong>en</strong>de patroon uit? Wat<br />

is D[i, j]? Er zijn drie gevall<strong>en</strong>.<br />

1. Als Pi = Tj dan is D[i, j] = D[i − 1, j − 1], als Pi �= Tj dan kunn<strong>en</strong> we substitutie pleg<strong>en</strong> <strong>en</strong> D[i, j] =<br />

D[i − 1, j − 1] + 1.<br />

2. D[i − 1, j] + 1, dat wil zegg<strong>en</strong> we voeg<strong>en</strong> e<strong>en</strong> letter in het patroon toe om het patroon op de tekst te<br />

lat<strong>en</strong> lijk<strong>en</strong>.<br />

3. D[i, j − 1] + 1, we lat<strong>en</strong> e<strong>en</strong> letter uit het patroon weg om het patroon op de tekst te lat<strong>en</strong> lijk<strong>en</strong>.<br />

Met deze regels kunn<strong>en</strong> we e<strong>en</strong> matrix vull<strong>en</strong>, het getal waarin we geinteresseerd zijn, dat de kost<strong>en</strong> geeft<br />

om het patroon helemaal gelijk te mak<strong>en</strong> aan de tekst, staat dan rechts onderin. Als we alle<strong>en</strong> geïnteresseerd<br />

zijn in gelijkheid <strong>van</strong> het patroon aan e<strong>en</strong> substring erg<strong>en</strong>s in T , zoals in e<strong>en</strong> edit programma, dan vind<strong>en</strong> we<br />

de kost<strong>en</strong> door het minimum <strong>van</strong> de laatste rij te nem<strong>en</strong>. We kunn<strong>en</strong> niet alle<strong>en</strong> de kost<strong>en</strong> vind<strong>en</strong>, maar door<br />

terugred<strong>en</strong>er<strong>en</strong> ook de plaatsing <strong>en</strong> de bijbehor<strong>en</strong>de operaties terugvind<strong>en</strong>. Bekijk het volg<strong>en</strong>de voorbeeld.<br />

Voorbeeld 2.3.3: In de tabel hieronder is de dynamisch programmer<strong>en</strong> algoritme toegepast op de tekst<br />

“...zijn spam-filters handig...” <strong>en</strong> het patroon “spam-fillers”—de werkelijke tekst is uiteraard veel langer,<br />

maar de bijbehor<strong>en</strong>de matrix zou niet prettig zijn voor de layout <strong>van</strong> de tekst.<br />

52


| z i j n s p a m - f i l t e r s h a n d i g<br />

----------------------------------------------------------------------------<br />

| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24<br />

s| 1 1 2 3 4 5 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23<br />

p| 2 2 2 3 4 5 6 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22<br />

a| 3 3 3 3 4 5 6 6 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21<br />

m| 4 4 4 4 4 5 6 7 6 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20<br />

-| 5 5 5 5 5 5 6 7 7 6 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19<br />

f| 6 6 6 6 6 6 6 7 8 7 6 5 6 7 8 9 10 11 12 13 14 15 16 17 18<br />

i| 7 7 6 7 7 7 7 7 8 8 7 6 5 6 7 8 9 10 11 12 13 14 15 16 17<br />

l| 8 8 7 7 8 8 8 8 8 9 8 7 6 5 6 7 8 9 10 11 12 13 14 15 16<br />

l| 9 9 8 8 8 9 9 9 9 9 9 8 7 6 6 7 8 9 10 11 12 13 14 15 16<br />

e|10 10 9 9 9 9 10 10 10 10 10 9 8 7 7 6 7 8 9 10 11 12 13 14 15<br />

r|11 11 10 10 10 10 10 11 11 11 11 10 9 8 8 7 6 7 8 9 10 11 12 13 14<br />

We zi<strong>en</strong> dat in de onderste kolom de minimale waarde 6 optreedt. Als we de diagonaal <strong>van</strong> dit getal<br />

terugvolg<strong>en</strong> zi<strong>en</strong> we dat deze één keer verkreg<strong>en</strong> wordt door substitutie (de t wordt in e<strong>en</strong> l veranderd), <strong>en</strong><br />

vijf keer door weglating <strong>van</strong> respectievelijk z,i,j,n, <strong>en</strong> e<strong>en</strong> spatie.<br />

✷<br />

2.3.3 Kortste pad<strong>en</strong> 2: Floyd-Warshall<br />

Bij de gulzige algoritm<strong>en</strong> in 2.1.3 hebb<strong>en</strong> we al gezi<strong>en</strong> hoe we de het kortste pad kunn<strong>en</strong> berek<strong>en</strong><strong>en</strong> tuss<strong>en</strong> e<strong>en</strong><br />

punt a <strong>en</strong> alle overige punt<strong>en</strong> uit de graaf. Stel nu dat we will<strong>en</strong> wet<strong>en</strong>, bijvoorbeeld om e<strong>en</strong> afstandstabel<br />

tuss<strong>en</strong> sted<strong>en</strong> te bouw<strong>en</strong>, wat het kortste pad is tuss<strong>en</strong> alle par<strong>en</strong> punt<strong>en</strong> <strong>van</strong> e<strong>en</strong> graaf. We kunn<strong>en</strong> dan<br />

Dijkstra’s algoritme toepass<strong>en</strong> op alle punt<strong>en</strong> <strong>van</strong> de graaf <strong>en</strong> zo de afstandstabel opbouw<strong>en</strong>. Er is echter ook<br />

nog e<strong>en</strong> andere methode, die past in dit hoofdstuk omdat het e<strong>en</strong> toepassing <strong>van</strong> dynamisch programmer<strong>en</strong><br />

is. De observatie die e<strong>en</strong> dynamic programming aanpak mogelijk maakt is dat we elk punt in de graaf<br />

afzonderlijk wel of juist niet toe kunn<strong>en</strong> lat<strong>en</strong> op e<strong>en</strong> af te legg<strong>en</strong> pad <strong>van</strong> a naar b. Als we ge<strong>en</strong> <strong>en</strong>kel<br />

intermediair punt toelat<strong>en</strong> op het pad <strong>van</strong> a naar b dan is het kortste pad simpel de l<strong>en</strong>gte <strong>van</strong> de kant <strong>van</strong><br />

a naar b (of ∞ als die kant niet bestaat), <strong>en</strong> als we het kortste pad wet<strong>en</strong> tuss<strong>en</strong> alle par<strong>en</strong> knop<strong>en</strong> in de<br />

graaf dat loopt over punt<strong>en</strong> uit {0, . . . , i} dan kunn<strong>en</strong> we het kortste pad in de graaf berek<strong>en</strong><strong>en</strong> dat loopt<br />

over punt<strong>en</strong> uit {0, . . . , i + 1}, door het korste pad wel of niet door i + 1 te lat<strong>en</strong> lop<strong>en</strong>. Het minimale pad<br />

<strong>van</strong> a naar b is dan of het minimale pad <strong>van</strong> a naar b dat alle<strong>en</strong> loopt langs knop<strong>en</strong> uit {0, . . . , i} of het<br />

minimale pad dat loopt <strong>van</strong> a naar i + 1 (uiteraard alle<strong>en</strong> via knop<strong>en</strong> uit {0, . . . , i}) geplakt voor het kortste<br />

pad dat loopt <strong>van</strong> knoop i + 1 naar b. Als i gelijk aan n is geword<strong>en</strong>, dan hebb<strong>en</strong> we het minimale pad dat<br />

kan lop<strong>en</strong> langs alle knop<strong>en</strong> <strong>van</strong> de graaf, dus het minimale pad.<br />

Voorbeeld 2.3.4: We beschrijv<strong>en</strong> e<strong>en</strong> graaf op 5 punt<strong>en</strong> door e<strong>en</strong> matrix waarin de gewicht<strong>en</strong> <strong>van</strong> de<br />

kant<strong>en</strong> staan. De graaf die we hier gebruik<strong>en</strong> heeft relatief veel kant<strong>en</strong> zodat e<strong>en</strong> tek<strong>en</strong>ing <strong>van</strong> de graaf wat<br />

onoverzichtelijk wordt. Die tek<strong>en</strong>ing is voor de illustratie <strong>van</strong> de algoritme ook niet zo belangrijk.<br />

⎛<br />

⎜<br />

⎝<br />

∞ 6 3 8 4<br />

7 ∞ 2 2 9<br />

7 ∞ ∞ 4 8<br />

7 8 3 ∞ 3<br />

9 8 ∞ 1 ∞<br />

De algoritme heeft 5 slag<strong>en</strong> waarin nieuwe knop<strong>en</strong> in het kortste pad word<strong>en</strong> toegelat<strong>en</strong>. Dat gaat als<br />

volgt. Telk<strong>en</strong>s wordt e<strong>en</strong> nieuwe knoop in het pad toegelat<strong>en</strong>. De corresponder<strong>en</strong>de kolom <strong>en</strong> rij word<strong>en</strong><br />

cursief afgedrukt. Als het pad via de nieuwe knoop korter is dan wat we al hadd<strong>en</strong> (het cursieve getal in<br />

dezelfde rij opgeteld bij het cursieve getal in dezelfde kolom), ver<strong>van</strong>g<strong>en</strong> we de waarde <strong>van</strong> het kortste pad<br />

door de nieuwe waarde. Aangezi<strong>en</strong> de l<strong>en</strong>gte <strong>van</strong> het pad naar de nieuwe knoop niet kan verander<strong>en</strong> door<br />

toevoeging <strong>van</strong> de nieuwe knoop blijv<strong>en</strong> de cursieve rij <strong>en</strong> de cursieve kolom dezelfde getall<strong>en</strong> houd<strong>en</strong>. De<br />

knop<strong>en</strong> waarvoor de afstand e<strong>en</strong> nieuwe waarde krijgt, drukk<strong>en</strong> we vet af.<br />

53<br />

⎞<br />

⎟<br />


⎛<br />

⎜<br />

⎝<br />

⎛<br />

⎜<br />

⎝<br />

∞ 6 3 8 4<br />

7 13 2 2 9<br />

7 13 10 4 8<br />

7 8 3 15 3<br />

9 8 12 1 13<br />

10 6 3 7 4<br />

7 10 2 2 5<br />

7 12 7 4 7<br />

7 8 3 7 3<br />

8 8 4 1 4<br />

⎞<br />

⎟<br />

⎠<br />

⎞<br />

⎟<br />

⎠<br />

⎛<br />

⎜<br />

⎝<br />

⎛<br />

⎜<br />

⎝<br />

13 6 3 8 4<br />

7 13 2 2 9<br />

7 13 10 4 8<br />

7 8 3 10 3<br />

9 8 10 1 13<br />

10 6 3 5 4<br />

7 10 2 2 5<br />

7 12 7 4 7<br />

7 8 3 4 3<br />

8 8 4 1 4<br />

⎞<br />

⎟<br />

⎠<br />

⎞<br />

⎟<br />

⎠<br />

⎛<br />

⎜<br />

⎝<br />

10 6 3 7 4<br />

7 13 2 2 9<br />

7 13 10 4 8<br />

7 8 3 7 3<br />

9 8 10 1 13<br />

We voer<strong>en</strong> in deze algoritme dus n slag<strong>en</strong> uit waarin we de informatie in de matrix over minimale<br />

verbinding<strong>en</strong> updat<strong>en</strong>. Elke update kost O(n 2 ) stapp<strong>en</strong>. Per elem<strong>en</strong>t do<strong>en</strong> we slechts twee vergelijking<strong>en</strong>.<br />

De algoritme kost in totaal dus O(n 3 ).<br />

2.3.4 Matrixverm<strong>en</strong>igvuldiging<br />

Voor het verm<strong>en</strong>igvuldig<strong>en</strong> <strong>van</strong> twee matrices hebb<strong>en</strong> we e<strong>en</strong> effici<strong>en</strong>te algoritme gezi<strong>en</strong> in 2.2.1. We beschouw<strong>en</strong><br />

hier het probleem <strong>van</strong> het verm<strong>en</strong>igvuldig<strong>en</strong> <strong>van</strong> e<strong>en</strong> rij matrices, die niet allemaal vierkant zijn.<br />

Twee matrices A <strong>en</strong> B kunn<strong>en</strong> met elkaar verm<strong>en</strong>igvuldigd word<strong>en</strong> als het aantal kolomm<strong>en</strong> <strong>van</strong> A overe<strong>en</strong>komt<br />

met het aantal rij<strong>en</strong> <strong>van</strong> B. Immers op plaats i, j in de productmatrix komt het inproduct <strong>van</strong><br />

de i de rij <strong>van</strong> A <strong>en</strong> de j-de kolom <strong>van</strong> B te staan. De i-de rij <strong>van</strong> A moet voor die berek<strong>en</strong>ing dus net<br />

zoveel elem<strong>en</strong>t<strong>en</strong> hebb<strong>en</strong> als de j-de kolom <strong>van</strong> B, <strong>en</strong> het aantal elem<strong>en</strong>t<strong>en</strong> <strong>van</strong> de i-de rij <strong>van</strong> A is gelijk aan<br />

het aantal kolomm<strong>en</strong> <strong>van</strong> A. Ev<strong>en</strong>zo is het aantal elem<strong>en</strong>t<strong>en</strong> in de j-de kolom <strong>van</strong> B gelijk aan het aantal<br />

rij<strong>en</strong> <strong>van</strong> B. Laat A e<strong>en</strong> n × m matrix zijn <strong>en</strong> B e<strong>en</strong> m × p matrix zijn. Het resultaat is dan e<strong>en</strong> matrix<br />

C met n rij<strong>en</strong> <strong>en</strong> p kolomm<strong>en</strong>. Het aantal verm<strong>en</strong>igvuldiging<strong>en</strong> dat hiervoor nodig is, is met de standaard<br />

matrixverm<strong>en</strong>igvuldigingsalgoritme n × m × p.<br />

Stel nu e<strong>en</strong>s dat we e<strong>en</strong> drietal matrices moet<strong>en</strong> verm<strong>en</strong>igvuldig<strong>en</strong> A × B × C, waarbij A e<strong>en</strong> 30 × 40<br />

matrix is, B e<strong>en</strong> 40 × 50 <strong>en</strong> C e<strong>en</strong> 50 × 60 matrix. We kunn<strong>en</strong> dit, aangezi<strong>en</strong> matrixverm<strong>en</strong>igvuldiging<br />

associatief is op twee manier<strong>en</strong> do<strong>en</strong> (AB)C of A(BC). In het eerste geval voer<strong>en</strong> we eerst 30 × 40 × 50<br />

verm<strong>en</strong>igvuldiging<strong>en</strong> uit om e<strong>en</strong> 30 × 50 matrix te krijg<strong>en</strong>. Vervolg<strong>en</strong>s verm<strong>en</strong>igvuldig<strong>en</strong> we deze 30 × 50<br />

matrix met C t<strong>en</strong> koste <strong>van</strong> 30×50×60 verm<strong>en</strong>igvuldiging<strong>en</strong>. In het tweede geval verm<strong>en</strong>igvuldig<strong>en</strong> we eerst<br />

B <strong>en</strong> C t<strong>en</strong> koste <strong>van</strong> 40×50×60 verm<strong>en</strong>igvuldiging<strong>en</strong> <strong>en</strong> de resulter<strong>en</strong>de 40×60 matrix verm<strong>en</strong>igvuldig<strong>en</strong> we<br />

met A t<strong>en</strong> koste <strong>van</strong> 30×40×60 verm<strong>en</strong>igvuldiging<strong>en</strong>. Beide operaties leid<strong>en</strong> tot e<strong>en</strong> 30×60 productmatrix,<br />

de <strong>en</strong>e keer t<strong>en</strong> koste <strong>van</strong> 60000 + 90000 = 150000 verm<strong>en</strong>igvuldiging<strong>en</strong> <strong>en</strong> de andere keer t<strong>en</strong> koste <strong>van</strong><br />

120000 + 72000 = 184000 verm<strong>en</strong>igvuldigin<strong>en</strong>. De volgorde <strong>van</strong> verm<strong>en</strong>igvuldig<strong>en</strong> is hier <strong>van</strong> belang.<br />

Stel dat we e<strong>en</strong> rij matrices A1, . . . , An hebb<strong>en</strong> die we met elkaar will<strong>en</strong> verm<strong>en</strong>igvuldig<strong>en</strong>, waarbij gegev<strong>en</strong><br />

is dat als Ai als Ai e<strong>en</strong> di−1 × di matrix is, dat dan Ai+1 e<strong>en</strong> di × di+1 matrix is, m.a.w. verm<strong>en</strong>igvuldiging<br />

is mogelijk. Hoe zull<strong>en</strong> wij de volgorde <strong>van</strong> verm<strong>en</strong>igvuldig<strong>en</strong> (i.e. het plaats<strong>en</strong> <strong>van</strong> de haakjes) bepal<strong>en</strong>?<br />

Doorwerk<strong>en</strong> <strong>van</strong> <strong>en</strong>ige voorbeeld<strong>en</strong> (zie Som 2.3.5) laat zi<strong>en</strong> dat gulzige method<strong>en</strong> niet werk<strong>en</strong>. De oplossing<br />

voor dit probleem bereik<strong>en</strong> we met de dynamisch programmer<strong>en</strong> aanpak. Immers, stel dat we optimaal uit<br />

de matrices di tot <strong>en</strong> met dk e<strong>en</strong> productmatrix met di−1 rij<strong>en</strong> <strong>en</strong> dk kolomm<strong>en</strong> will<strong>en</strong> mak<strong>en</strong>. Het buit<strong>en</strong>ste<br />

paar haakjes moet erg<strong>en</strong>s tuss<strong>en</strong> i <strong>en</strong> k gezet word<strong>en</strong>, zeg op plaats j. Het aantal verm<strong>en</strong>igvuldiging<strong>en</strong> is nu<br />

gelijk aan di−1 × dj × dk plus het aantal verm<strong>en</strong>igvuldiging<strong>en</strong> dat nodig is om optimaal de rij matrices <strong>van</strong><br />

i tot j te verm<strong>en</strong>igvuldig<strong>en</strong> plus het aantal verm<strong>en</strong>igvuldiging<strong>en</strong> dat nodig is om optimaal de rij matrices<br />

<strong>van</strong> j tot k te verm<strong>en</strong>igvuldig<strong>en</strong>. Door deze getall<strong>en</strong> uit te rek<strong>en</strong><strong>en</strong> voor j lop<strong>en</strong>d <strong>van</strong> i naar k kunn<strong>en</strong> we<br />

achter het optimale getal kom<strong>en</strong>, waarbij het optimale aantal verm<strong>en</strong>igvuldiging<strong>en</strong> om twee ope<strong>en</strong>volg<strong>en</strong>de<br />

matrices te verm<strong>en</strong>igvuldig<strong>en</strong> vast ligt. Dit nodigt uit tot e<strong>en</strong> recursieve algoritme, ware het niet dat de<br />

recursieve boom die aldus onstaat alle mogelijke plaatsing <strong>van</strong> haakjespar<strong>en</strong> in e<strong>en</strong> knoop repres<strong>en</strong>teert. Het<br />

54<br />

⎞<br />

⎟<br />

⎠<br />


aantal mogelijkhed<strong>en</strong> dat dit oplevert is e<strong>en</strong> bek<strong>en</strong>d getal, het zog<strong>en</strong>aamde Catalaanse getal <strong>en</strong> is ongeveer<br />

4 n /n 3/2 . Dit levert dus ge<strong>en</strong> effici<strong>en</strong>te algoritme op. Als we echter voor alle par<strong>en</strong> j tuss<strong>en</strong> i <strong>en</strong> k het<br />

optimale getal k<strong>en</strong>n<strong>en</strong>, dan kunn<strong>en</strong> we met bov<strong>en</strong>beschrev<strong>en</strong> methode in ongeveer k − i stapp<strong>en</strong> uitrek<strong>en</strong><strong>en</strong><br />

wat het minimum is voor i tot k. Deze methode nodigt dus ook uit tot de dynamisch programmer<strong>en</strong> aanpak,<br />

<strong>en</strong> e<strong>en</strong> handige manier om deze te implem<strong>en</strong>ter<strong>en</strong> levert e<strong>en</strong> O(n 2 ) algoritme als volgt.<br />

Neem e<strong>en</strong> vierkante matrix P <strong>van</strong> n×n getall<strong>en</strong>. Omdat we wet<strong>en</strong> hoeveel verm<strong>en</strong>igvuldiging<strong>en</strong> optimaal<br />

zijn om de matrices op plaats i <strong>en</strong> i + 1 met elkaar te verm<strong>en</strong>igvuldig<strong>en</strong> (di−1 × di × di+1) kunn<strong>en</strong> we al deze<br />

getall<strong>en</strong> op plaats i, i + 1 in de matrix invull<strong>en</strong> (formeel kan ook de diagnonaal gevuld word<strong>en</strong> met 0). Nu<br />

vull<strong>en</strong> we de rest <strong>van</strong> de matrix met de formule<br />

P [i, j] = min{P [i, k] + P [k + 1, j] + di−1 × dk × dj : i < k < j}.<br />

Omdat we de waard<strong>en</strong> P [i, i + 1] in deze matrix wet<strong>en</strong>, kunn<strong>en</strong> we hem in O(n 2 ) stapp<strong>en</strong> (waarbij elke stap<br />

niet meer dan het vind<strong>en</strong> <strong>van</strong> het minimum in e<strong>en</strong> rij <strong>van</strong> l<strong>en</strong>gte n kost) verder invull<strong>en</strong>. De complexiteit<br />

<strong>van</strong> de algoritme is dus O(n 3 ).<br />

Voorbeeld 2.3.5: Laat gegev<strong>en</strong> e<strong>en</strong> zijn e<strong>en</strong> rijtje matrices met de volg<strong>en</strong>de dim<strong>en</strong>sies<br />

18 × 31, 31 × 40, 40 × 29, 29 × 9, 9 × 11, 11 × 8, 8 × 20, 20 × 44, 44 × 31<br />

Uit de bov<strong>en</strong>beschrev<strong>en</strong> algoritme komt de volg<strong>en</strong>de matrix.<br />

⎛<br />

0<br />

⎜<br />

⎝<br />

22320<br />

0<br />

43200<br />

35960<br />

0<br />

26622<br />

21600<br />

10440<br />

0<br />

28404<br />

24669<br />

14400<br />

2871<br />

0<br />

26544<br />

22080<br />

12160<br />

2880<br />

792<br />

0<br />

29424<br />

27040<br />

18560<br />

7452<br />

2232<br />

1760<br />

0<br />

39920<br />

40032<br />

33280<br />

20128<br />

10152<br />

10912<br />

7040<br />

0<br />

⎞<br />

48960<br />

47720 ⎟<br />

40032 ⎟<br />

28024 ⎟<br />

20976 ⎟<br />

20680 ⎟<br />

17952 ⎟<br />

27280 ⎠<br />

0<br />

Waaruit we kunn<strong>en</strong> zi<strong>en</strong> dat de meest gunstige manier om deze matrices te verm<strong>en</strong>igvuldig<strong>en</strong> 48960<br />

verm<strong>en</strong>igvuldiging<strong>en</strong> kost. Om de volgorde te bepal<strong>en</strong> waarmee dat lukt is het nodig tuss<strong>en</strong>resultat<strong>en</strong> op te<br />

slaan. In ons geval is de optimale volgorde:<br />

(1 × (2 × (3 × 4 × (5 × 6)))) × ((7 × 8) × 9)<br />

Naast de aantall<strong>en</strong> verm<strong>en</strong>igvuldiging<strong>en</strong>, moet<strong>en</strong> we daarvoor ook bijhoud<strong>en</strong> welke matrices met elkaar<br />

verm<strong>en</strong>igvuldigd word<strong>en</strong>. In de volg<strong>en</strong>de matrix staan op plaats (i, j) telk<strong>en</strong>s het hoogste niveau haakjes.<br />

E<strong>en</strong> × betek<strong>en</strong>t dat twee naast elkaar geleg<strong>en</strong> matrices rechtstreeks verm<strong>en</strong>igvuldigd moet word<strong>en</strong> <strong>en</strong> i ⇀ j<br />

betek<strong>en</strong>t dat op plaats i, j gekek<strong>en</strong> moet word<strong>en</strong> hoe deze rij optimaal verm<strong>en</strong>igvuldigd kan word<strong>en</strong>.<br />

⎛<br />

⎜<br />

⎝<br />

1 × 2 (1 × 2)3 1(2 ⇀ 4) (1 ⇀ 4)5 1(2 ⇀ 6) (1 ⇀ 6)7 (1 ⇀ 6) × (7 × 8) (1 ⇀ 6) × (7 ⇀ 9)<br />

2 × 3 2(3 × 4) (2 ⇀ 4)5 2(3 ⇀ 6) (2 ⇀ 6)7 (2 ⇀ 6) × (7 × 8) (2 ⇀ 6) × (7 ⇀ 9)<br />

3 × 4 (3 × 4)5 3(4 ⇀ 6) (3 ⇀ 6)7 (3 ⇀ 6) × (7 × 8) (3 ⇀ 6) × (7 ⇀ 9)<br />

4 × 5 4(5 × 6) 4(5 ⇀ 7) (4 ⇀ 6) × (7 × 8) (4 ⇀ 6) × (7 ⇀ 9)<br />

5 × 6 (5 × 6)7 (5 ⇀ 7)8 (5 × 6) × (7 ⇀ 9)<br />

6 × 7 6(7 × 8) 6(7 ⇀ 9)<br />

7 × 8 (7 × 8)9<br />

8 × 9<br />

55<br />

⎞<br />

⎟<br />

⎠<br />


2.3.5 Somm<strong>en</strong><br />

1. Laat zi<strong>en</strong> met behulp <strong>van</strong> voorbeeld<strong>en</strong> dat gulzige algoritm<strong>en</strong> voor matrix-ketting-verm<strong>en</strong>igvuldiging<br />

gebaseerd op<br />

(a) Neem de kleinste product<strong>en</strong> (minimaliseer di−1 × di × di+1 eerst).<br />

(b) Neem de grootste product<strong>en</strong> (maximaliseer di−1 × di × di+1 eerst).<br />

niet werk<strong>en</strong>. Kun je nog andere gulzige heuristiek<strong>en</strong> bed<strong>en</strong>k<strong>en</strong>?<br />

2. Vind dynamisch programmer<strong>en</strong> oplossing voor de volg<strong>en</strong>de problem<strong>en</strong>. Het volstaat de recurr<strong>en</strong>tie te<br />

vind<strong>en</strong>.<br />

(a) E<strong>en</strong> gokker begint met 3 euro <strong>en</strong> wil in drie keer gokk<strong>en</strong> vijf euro hebb<strong>en</strong>. Bij elke gok is de kans<br />

op winst 2/3 <strong>en</strong> bij winst wordt twee keer de inzet uitbetaald (bij verlies is de inzet verlor<strong>en</strong>).<br />

Bepaal met e<strong>en</strong> e<strong>en</strong> dynamisch programma de strategie (hoeveel moet zij inzett<strong>en</strong>) om de kans te<br />

maximaliser<strong>en</strong>.<br />

(b) Langste stijg<strong>en</strong>de subrij. Gegev<strong>en</strong> e<strong>en</strong> rij getall<strong>en</strong>, vind de langste deelrij waar<strong>van</strong> de elem<strong>en</strong>t<strong>en</strong><br />

monotoon stijg<strong>en</strong>d zijn (ze hoev<strong>en</strong> niet naast elkaar te staan). Dus bijvoorbeeld <strong>van</strong> S =<br />

(9, 5, 2, 8, 7, 3, 1, 6, 4) heeft de langste stijg<strong>en</strong>de deelrij l<strong>en</strong>gte drie <strong>en</strong> is (2, 3, 4) of (2, 3, 6).<br />

(c) Maximale som. Vind in e<strong>en</strong> rij getall<strong>en</strong> de deelrij <strong>van</strong> naast elkaar ligg<strong>en</strong>de getall<strong>en</strong> met maximale<br />

som (bijvoorbeeld in {31, −41, 59, 26, −53, 58, 97, −123, 93, 84} is dat de rij <strong>van</strong> 59 t.e.m. 97).<br />

(d) Kleur<strong>en</strong>. n auto’s hebb<strong>en</strong> c kleur<strong>en</strong> <strong>en</strong> kunn<strong>en</strong> k plaats<strong>en</strong> versleept word<strong>en</strong>. Zoek de rij met het<br />

minimaal aantal kleurwisseling<strong>en</strong>. Bijvoorbeeld: 011200121 kan met k = 2 word<strong>en</strong> veranderd in<br />

110002211.<br />

(e) Play Offs. Team A <strong>en</strong> team B spel<strong>en</strong> e<strong>en</strong> serie <strong>van</strong> niet meer dan 2n − 1 wedstrijd<strong>en</strong> teg<strong>en</strong> elkaar.<br />

E<strong>en</strong> team heeft de serie gewonn<strong>en</strong> zodra het n of meer wedstrijd<strong>en</strong> gewonn<strong>en</strong> heeft. Er bestaat<br />

ge<strong>en</strong> gelijkspel <strong>en</strong> de wedstrijd<strong>en</strong> zijn onafhankelijk <strong>van</strong> elkaar. Voor elke wedstrijd is er e<strong>en</strong><br />

constante waarschijnlijkheid p dat team A wint (<strong>en</strong> dus e<strong>en</strong> constante waarschijnlijkheid 1 − p dat<br />

team B wint). Berek<strong>en</strong> de kans dat team A wint.<br />

(f) Shuffle. Stel je krijgt drie rijtjes letters:X = x1, x2, . . . , xm, Y = y1y2, . . . , yn <strong>en</strong> Z = z1, z2, . . . , zm+n.<br />

Z is e<strong>en</strong> shuffle <strong>van</strong> X <strong>en</strong> Y als Z gemaakt kan word<strong>en</strong> door om beurt<strong>en</strong> e<strong>en</strong> stukje <strong>van</strong> X <strong>en</strong> e<strong>en</strong><br />

stukje <strong>van</strong> Y te nem<strong>en</strong>, waarbij de letters in volgorde blijv<strong>en</strong> staan. Bijvoorbeeld, cchocohilaptes<br />

is e<strong>en</strong> shuffle <strong>van</strong> chocolate em <strong>en</strong> chips, maar cchocolhilaptes is dat niet. Gegev<strong>en</strong> X, Y, Z, m <strong>en</strong><br />

n. Is Z wel of niet e<strong>en</strong> shuffle <strong>van</strong> X <strong>en</strong> Y ?<br />

Programmer<strong>en</strong><br />

1. Maak e<strong>en</strong> ongerichte volledige graaf op 25 knop<strong>en</strong> <strong>en</strong> geef de kant<strong>en</strong> random waard<strong>en</strong> tuss<strong>en</strong> de 1 <strong>en</strong><br />

de 100. Berek<strong>en</strong> tuss<strong>en</strong> elk tweetal punt<strong>en</strong> de l<strong>en</strong>gte <strong>van</strong> het kortste pad. Doe vervolg<strong>en</strong>s hetzelfde met<br />

de algoritme <strong>van</strong> Floyd-Warshall <strong>en</strong> vergelijk de uitkomst<strong>en</strong>.<br />

56


Hoofdstuk 3<br />

Graf<strong>en</strong>algoritm<strong>en</strong><br />

E<strong>en</strong> belangrijk onderdeel <strong>van</strong> de algoritmiek wordt gevormd door de specifieke toepassing <strong>van</strong> algoritm<strong>en</strong> in de<br />

graf<strong>en</strong>theorie. E<strong>en</strong> aantal typische graafalgoritm<strong>en</strong> hebb<strong>en</strong> we al besprok<strong>en</strong> in Hoofdstuk 2 omdat ze de in die<br />

sectie besprok<strong>en</strong> techniek uitstek<strong>en</strong>d toelicht<strong>en</strong>. E<strong>en</strong> aantal typische graf<strong>en</strong>problem<strong>en</strong> zull<strong>en</strong> nog uitgebreid<br />

aan bod kom<strong>en</strong> in 6.5 <strong>van</strong>wege het feit dat er ge<strong>en</strong> effici<strong>en</strong>te algoritme voor het algem<strong>en</strong>e probleem bek<strong>en</strong>d<br />

is. Voor e<strong>en</strong> aantal e<strong>en</strong>voudig te beschrijv<strong>en</strong> <strong>en</strong> veelvoorkom<strong>en</strong>de graf<strong>en</strong>problem<strong>en</strong> wet<strong>en</strong> we ge<strong>en</strong> andere<br />

oplossing te bed<strong>en</strong>k<strong>en</strong> dan alle mogelijke oplossing<strong>en</strong> te g<strong>en</strong>erer<strong>en</strong> <strong>en</strong> daaruit e<strong>en</strong> pass<strong>en</strong>de te kiez<strong>en</strong>. Omdat<br />

het totaal aantal mogelijke oplossing<strong>en</strong> vaak expon<strong>en</strong>tieel is, zegg<strong>en</strong> we dat zo’n graf<strong>en</strong>probleem ondo<strong>en</strong>lijk<br />

is <strong>en</strong> zoek<strong>en</strong> we naar inperking<strong>en</strong> <strong>van</strong> de soort graf<strong>en</strong> waarop het aantal mogelijke oplossing<strong>en</strong> beperkt is, of<br />

waarop de algoritme verder kan word<strong>en</strong> gespecialiseerd, zodat niet alle oplossing<strong>en</strong> bekek<strong>en</strong> hoev<strong>en</strong> word<strong>en</strong>.<br />

Te d<strong>en</strong>k<strong>en</strong> valt hierbij aan graf<strong>en</strong> met beperkte graad, beperkte diepte (padl<strong>en</strong>gte), beperkte boombreedte<br />

of andere speciale eig<strong>en</strong>schapp<strong>en</strong> zoals planariteit. Het onderzoek naar graf<strong>en</strong>algoritm<strong>en</strong> beweegt zich voor<br />

e<strong>en</strong> belangrijk deel op dit gebied. In dit hoofdstuk zull<strong>en</strong> we nog e<strong>en</strong> paar algem<strong>en</strong>e method<strong>en</strong> besprek<strong>en</strong><br />

voor het doorzoek<strong>en</strong> <strong>en</strong> klassificer<strong>en</strong> <strong>van</strong> graf<strong>en</strong>. We beginn<strong>en</strong> met doorzoek<strong>en</strong>.<br />

3.1 Zoek<strong>en</strong> in Graf<strong>en</strong><br />

E<strong>en</strong> graaf bestaat uit knop<strong>en</strong> <strong>en</strong> kant<strong>en</strong> <strong>en</strong> de structuur <strong>van</strong> e<strong>en</strong> graaf kunn<strong>en</strong> we onderzoek<strong>en</strong> door <strong>van</strong> de<br />

<strong>en</strong>e knoop naar de andere knoop te lop<strong>en</strong> met behulp <strong>van</strong> e<strong>en</strong> algoritme. Aangezi<strong>en</strong> e<strong>en</strong> knoop doorgaans<br />

door meerdere kant<strong>en</strong> aan meerdere andere knop<strong>en</strong> verbond<strong>en</strong> is, moet<strong>en</strong> we in elke knoop e<strong>en</strong> keuze mak<strong>en</strong><br />

welke knoop de volg<strong>en</strong>de in de rij is (of meer precies welke knoop na de volg<strong>en</strong>de knoop in de rij zal volg<strong>en</strong>).<br />

Er zijn twee hoofdkeuz<strong>en</strong> die de soort zoekalgoritme bepal<strong>en</strong>, de overige method<strong>en</strong> zijn variaties daarop.<br />

3.1.1 Depth First Search<br />

In de diepte eerst methode, wordt het volg<strong>en</strong>de te bezoek<strong>en</strong> punt gekoz<strong>en</strong> door eerst zo diep mogelijk in de<br />

graaf te gaan <strong>en</strong> pas daarna nog onbezochte knop<strong>en</strong> die bur<strong>en</strong> zijn <strong>van</strong> eerder bezochte knop<strong>en</strong> te onderzoek<strong>en</strong>.<br />

We nem<strong>en</strong> aan dat de knop<strong>en</strong> <strong>van</strong> de graaf g<strong>en</strong>ummerd zijn, zodat we in e<strong>en</strong> knoop als volg<strong>en</strong>de knoop de<br />

knoop met het laagste nummer kunn<strong>en</strong> kiez<strong>en</strong>. Ook nem<strong>en</strong> we aan dat we e<strong>en</strong> merktek<strong>en</strong> “bezocht” op e<strong>en</strong><br />

knoop kunn<strong>en</strong> aanbr<strong>en</strong>g<strong>en</strong>.<br />

1: Procedure DFS(v: knoop)<br />

2: Markeer v bezocht.<br />

3: while ∃w buurknoop <strong>van</strong> v die nog niet bezocht is do<br />

4: Neem zo’n w met minimale index;<br />

5: DFS(w);<br />

6: <strong>en</strong>d while<br />

57


De procedure voor diep zoek<strong>en</strong> eerst, Depth First Search (DFS), is efficiënt <strong>en</strong> bijzonder e<strong>en</strong>voudig op<br />

te schrijv<strong>en</strong>. Als we aannem<strong>en</strong> dat het aflop<strong>en</strong> <strong>van</strong> e<strong>en</strong> kant in constante tijd kan, dan neemt DFS niet<br />

meer tijd dan er knop<strong>en</strong> zijn, <strong>en</strong> is dus O(n). Zoiets zou bijvoorbeeld kunn<strong>en</strong> wanneer de graaf gegev<strong>en</strong> is<br />

als e<strong>en</strong> adjac<strong>en</strong>cy matrix <strong>en</strong> we dus directe toegang tot de kant<strong>en</strong> hebb<strong>en</strong>. Andere implem<strong>en</strong>taties vereis<strong>en</strong><br />

misschi<strong>en</strong> eerst sorter<strong>en</strong> <strong>van</strong> de knop<strong>en</strong> (O(n log n)), of <strong>van</strong> de kant<strong>en</strong> (O(m log m) ⊆ O(n 2 log n)). Hoe<br />

ook, de procedure blijft buit<strong>en</strong>gewoon effici<strong>en</strong>t. Met behulp <strong>van</strong> deze zoekmethod<strong>en</strong> kunn<strong>en</strong> we diverse<br />

eig<strong>en</strong>schapp<strong>en</strong> <strong>van</strong> e<strong>en</strong> graaf id<strong>en</strong>tificer<strong>en</strong>.<br />

De procedure DFS selecteert e<strong>en</strong> aantal kant<strong>en</strong> in de graaf <strong>en</strong> stelt de graaf voor als e<strong>en</strong> boom. Doorgaans<br />

heeft de graaf natuurlijk nog veel meer kant<strong>en</strong>. De kant<strong>en</strong> die door DFS gebruikt word<strong>en</strong> om de graaf te<br />

doorlop<strong>en</strong> zull<strong>en</strong> we boomkant<strong>en</strong> (tree-edges) noem<strong>en</strong>. De kant<strong>en</strong> in de graaf die <strong>van</strong> e<strong>en</strong> knoop v terugwijz<strong>en</strong><br />

naar e<strong>en</strong> knoop w die e<strong>en</strong> voorouder is <strong>van</strong> v in de DFS boom zull<strong>en</strong> we terugkant<strong>en</strong> (back-edges) noem<strong>en</strong><br />

<strong>en</strong> de kant<strong>en</strong> die niet in deze categorie vall<strong>en</strong> (dus verschill<strong>en</strong>de pad<strong>en</strong> <strong>van</strong> de boom met elkaar verbind<strong>en</strong>)<br />

zull<strong>en</strong> we kruiskant<strong>en</strong> noem<strong>en</strong>. In het voorbeeldje hieronder zull<strong>en</strong> we de boomkant<strong>en</strong> <strong>van</strong> de graaf aangev<strong>en</strong><br />

met pijl<strong>en</strong>, de terugkant<strong>en</strong> met gestreepte pijl<strong>en</strong> <strong>en</strong> de kruiskant<strong>en</strong> met ⇒.<br />

Voorbeeld 3.1.1: Bekijk de graaf G op 9 knop<strong>en</strong> met 16 kant<strong>en</strong>. Deze graaf wordt door DFS in de figuur<br />

DFS(G) als boom beschrev<strong>en</strong>.<br />

G DFS(G)<br />

•1 ��<br />

•2 ��<br />

•3 ��<br />

��<br />

•1 ��<br />

��<br />

•4 ��<br />

��<br />

��<br />

•5 ��<br />

��<br />

•6 ��<br />

•7 ��<br />

Cykels<br />

��<br />

•8 ��<br />

��<br />

•9 ��<br />

��<br />

•2 ��<br />

4 • ��<br />

��<br />

��<br />

��<br />

��<br />

• 3 • 5<br />

• 6<br />

��<br />

��<br />

��<br />

��<br />

��<br />

��<br />

• 9 • 8<br />

Met DFS kan word<strong>en</strong> bepaald of in e<strong>en</strong> graaf cykels zitt<strong>en</strong>. Immers, als er e<strong>en</strong> cykel in e<strong>en</strong> graaf zit, dan<br />

kom<strong>en</strong> we met DFS langs e<strong>en</strong> pad aan op e<strong>en</strong> knoop die reeds gemarkeerd is, <strong>en</strong> anders kom<strong>en</strong> we alle<strong>en</strong> terug<br />

uit de recursie bij reeds gemarkeerde knop<strong>en</strong>. E<strong>en</strong> <strong>en</strong>kele DFS run kan besliss<strong>en</strong> of er e<strong>en</strong> cykel is die door<br />

e<strong>en</strong> gegev<strong>en</strong> knoop voert. Om te besliss<strong>en</strong> of er e<strong>en</strong> cykel in de graaf is, kunn<strong>en</strong> we DFS achtere<strong>en</strong>volg<strong>en</strong>s<br />

uit alle knop<strong>en</strong> uit de graaf start<strong>en</strong>.<br />

58<br />

• 7<br />

��<br />


Topological Sort<br />

E<strong>en</strong> acyclische graaf kan de voorstelling zijn <strong>van</strong> e<strong>en</strong> partiële ord<strong>en</strong>ing 1 . Soms kan het nodig zijn <strong>van</strong> e<strong>en</strong><br />

partiële ord<strong>en</strong>ing e<strong>en</strong> totale ord<strong>en</strong>ing te mak<strong>en</strong>. Te d<strong>en</strong>k<strong>en</strong> bijvoorbeeld valt aan machinevolgordeproblem<strong>en</strong><br />

waarbij afhankelijkhed<strong>en</strong> bestaan tuss<strong>en</strong> tak<strong>en</strong> uit te voer<strong>en</strong> door e<strong>en</strong> machine. Deze afhankelijkhed<strong>en</strong><br />

definiër<strong>en</strong> e<strong>en</strong> partiële ord<strong>en</strong>ing die platgeslag<strong>en</strong> di<strong>en</strong>t te word<strong>en</strong> tot e<strong>en</strong> lineaire ord<strong>en</strong>ing om op e<strong>en</strong> machine<br />

te kunn<strong>en</strong> word<strong>en</strong> uitgevoerd. Ook zi<strong>en</strong> we het topological sort probleem vaak optred<strong>en</strong> bij het gebruik <strong>van</strong><br />

databases, waarbij transacties die gebruik mak<strong>en</strong> <strong>van</strong> dezelfde resources op elkaar moet<strong>en</strong> wacht<strong>en</strong>. Het<br />

probleem is dan het vind<strong>en</strong> <strong>van</strong> e<strong>en</strong> volgorde waarin de transacties kunn<strong>en</strong> word<strong>en</strong> uitgevoerd, of waarin de<br />

transacties zoud<strong>en</strong> kunn<strong>en</strong> zijn uitgevoerd als ze door e<strong>en</strong> machine zoud<strong>en</strong> zijn behandeld (serializability).<br />

We zoud<strong>en</strong> kunn<strong>en</strong> prober<strong>en</strong> voor dit probleem DFS in te zett<strong>en</strong>, maar DFS respecteert niet noodzakelijk<br />

alle afhankelijkhed<strong>en</strong> in de graaf. E<strong>en</strong> graafje als bijvoorbeeld<br />

• 1<br />

��<br />

��<br />

•2 ��<br />

•3 wordt door DFS in de volgorde 1, 2, 3 doorlop<strong>en</strong>, maar de afhankelijkheid 2 ← 3 maakt dat deze volgorde<br />

niet legitiem is voor topological sort.<br />

We hebb<strong>en</strong> dus e<strong>en</strong> andere algoritme nodig voor het vind<strong>en</strong> <strong>van</strong> deze ord<strong>en</strong>ing. De observatie die we<br />

mak<strong>en</strong> is dat er in e<strong>en</strong> acyclische graaf altijd minst<strong>en</strong>s één knoop moet zijn met ingraad 0. Begin in e<strong>en</strong><br />

willekeurige knoop, kies e<strong>en</strong> willekeurige inkom<strong>en</strong>de kant <strong>en</strong> ga naar de knoop die aan de andere kant zit.<br />

Aangezi<strong>en</strong> de graaf acyclisch is, moet deze actie altijd e<strong>en</strong> nieuwe knoop oplever<strong>en</strong>, <strong>en</strong> dat kan niet meer dan<br />

n keer. De knoop met ingraad 0 hoeft niet later in de ord<strong>en</strong>ing te kom<strong>en</strong> dan <strong>en</strong>ige andere knoop in de graaf<br />

<strong>en</strong> kan dus de eerste in de ord<strong>en</strong>ing zijn. Deze knoop gev<strong>en</strong> we dus nummer 1 in de volgorde, we verwijder<strong>en</strong><br />

de knoop <strong>en</strong> voer<strong>en</strong> de actie opnieuw voor de rester<strong>en</strong>de knop<strong>en</strong> (die ook e<strong>en</strong> acyclische graaf vorm<strong>en</strong>) uit.<br />

1: Procedure TopSort(G,n)<br />

2: if G �= ∅ th<strong>en</strong><br />

3: Find v with indegree 0;<br />

4: Give v number n;<br />

5: TopSort(G − {v}, n + 1)<br />

6: <strong>en</strong>d if<br />

Verbond<strong>en</strong> Compon<strong>en</strong>t<strong>en</strong><br />

E<strong>en</strong> verbond<strong>en</strong> compon<strong>en</strong>t in e<strong>en</strong> graaf is e<strong>en</strong> deel <strong>van</strong> de graaf met de eig<strong>en</strong>schap dat tuss<strong>en</strong> elk tweetal<br />

punt<strong>en</strong> t<strong>en</strong>minste één pad loopt. Zowel gerichte als ongerichte graf<strong>en</strong> hebb<strong>en</strong> verbond<strong>en</strong> compon<strong>en</strong>t<strong>en</strong>, maar<br />

in ongerichte graf<strong>en</strong> loopt tuss<strong>en</strong> elk tweetal punt<strong>en</strong> natuurlijk zowel e<strong>en</strong> pad he<strong>en</strong> als e<strong>en</strong> pad terug. Dat is in<br />

gerichte graf<strong>en</strong> niet altijd het geval. Als in e<strong>en</strong> deel <strong>van</strong> e<strong>en</strong> gerichte graaf tuss<strong>en</strong> elk tweetal punt<strong>en</strong> zowel e<strong>en</strong><br />

pad he<strong>en</strong> als e<strong>en</strong> pad terug loopt, noem<strong>en</strong> we zo’n deel dubbelverbond<strong>en</strong> of sterkverbond<strong>en</strong> (bi-connected of<br />

strongly connected). Depth First Search is natuurlijk e<strong>en</strong> uitgelez<strong>en</strong> algoritme om verbond<strong>en</strong> compon<strong>en</strong>t<strong>en</strong><br />

te vind<strong>en</strong>. Immers, als we e<strong>en</strong> Depth First Search in e<strong>en</strong> punt start<strong>en</strong>, dan vind<strong>en</strong> we alle punt<strong>en</strong> in de<br />

graaf die door e<strong>en</strong> pad met dat punt verbond<strong>en</strong> zijn, ofwel we vind<strong>en</strong> alle punt<strong>en</strong> in de graaf die in dezelfde<br />

verbond<strong>en</strong> compon<strong>en</strong>t zitt<strong>en</strong> als dit punt. DFS kan echter ook gebruikt word<strong>en</strong> om de dubbelverbond<strong>en</strong><br />

compon<strong>en</strong>t<strong>en</strong> <strong>van</strong> e<strong>en</strong> gerichte graaf te ontdekk<strong>en</strong>.<br />

1 E<strong>en</strong> ord<strong>en</strong>ing op e<strong>en</strong> verzameling kan partiëel of totaal zijn. Als e<strong>en</strong> ord<strong>en</strong>ing,


Articulation Points<br />

E<strong>en</strong> articulation point in e<strong>en</strong> graaf is e<strong>en</strong> punt dat de graaf in twee del<strong>en</strong> verdeelt, zo dat elk pad <strong>van</strong> het<br />

<strong>en</strong>e deel <strong>van</strong> de graaf naar het andere deel <strong>van</strong> de graaf door dit punt moet gaan. Articulation points in<br />

netwerk<strong>en</strong> zijn vaak de kwetsbare punt<strong>en</strong>. Neem je de articulation points uit e<strong>en</strong> verbond<strong>en</strong> graaf weg, dan<br />

valt de graaf uite<strong>en</strong> in e<strong>en</strong> aantal verbond<strong>en</strong> compon<strong>en</strong>t<strong>en</strong>. In dataverkeer tuss<strong>en</strong> computers will<strong>en</strong> we niet<br />

graag articulation points hebb<strong>en</strong> omdat uitval <strong>van</strong> dit punt het einde <strong>van</strong> de communicatie betek<strong>en</strong>t. Als<br />

articulation points om welke red<strong>en</strong> dan ook onvermijdelijk zijn, dan will<strong>en</strong> we er graag zo weinig mogelijk<br />

hebb<strong>en</strong>.<br />

In 3.1.1 hebb<strong>en</strong> we al gezi<strong>en</strong> hoe we met behulp <strong>van</strong> DFS verbond<strong>en</strong> compon<strong>en</strong>t<strong>en</strong> kond<strong>en</strong> id<strong>en</strong>tificer<strong>en</strong>.<br />

Net zo makkelijk kunn<strong>en</strong> we natuurlijk articulation points met behulp <strong>van</strong> DFS id<strong>en</strong>tificer<strong>en</strong>. Bijvoorbeeld:<br />

neem zo’n punt uit de graaf. Twee bur<strong>en</strong> <strong>van</strong> dit punt kom<strong>en</strong> dan in verschill<strong>en</strong>de verbond<strong>en</strong> compon<strong>en</strong>t<strong>en</strong><br />

te zitt<strong>en</strong>. Aan de volledige DFS boom <strong>van</strong> e<strong>en</strong> verbond<strong>en</strong> compon<strong>en</strong>t kunn<strong>en</strong> we echter de articulation points<br />

nog gemakkelijker herk<strong>en</strong>n<strong>en</strong>. Bekijk e<strong>en</strong> DFS boom <strong>en</strong> neem e<strong>en</strong> punt dat niet de wortel <strong>van</strong> de boom is.<br />

Als dit punt e<strong>en</strong> articulation point is, dan moet de graaf na het wegnem<strong>en</strong> <strong>van</strong> dit punt uit t<strong>en</strong>minste twee<br />

compon<strong>en</strong>t<strong>en</strong> bestaan die niet met elkaar verbond<strong>en</strong> zijn. Alle punt<strong>en</strong> in de graaf die niet in de subboom <strong>van</strong><br />

dit punt zitt<strong>en</strong>, kunn<strong>en</strong> <strong>van</strong>uit de wortel bereikt word<strong>en</strong>. De graaf kan na weglating <strong>van</strong> dit punt dus alle<strong>en</strong><br />

maar uit twee niet met elkaar verbond<strong>en</strong> compon<strong>en</strong>t<strong>en</strong> bestaan, als de subboom <strong>van</strong> dit punt ge<strong>en</strong> andere<br />

verbinding (terugkant<strong>en</strong> of kruiskant<strong>en</strong>) heeft met de rest <strong>van</strong> de graaf. Dit kunn<strong>en</strong> we met e<strong>en</strong> recursieve<br />

procedure nagaan.<br />

3.1.2 Breadth First Search<br />

De alternatieve manier om recursief e<strong>en</strong> graaf te doorzoek<strong>en</strong> is de “breedte eerst” methode. In plaats <strong>van</strong> eerst<br />

zo diep mogelijk in de graaf te gaan, bezoek<strong>en</strong> we eerst de hele buurt <strong>van</strong> de knoop waar we zijn, om daarna<br />

alle knop<strong>en</strong> die <strong>van</strong> deze bur<strong>en</strong> weer bur<strong>en</strong> zijn te bezoek<strong>en</strong>. Depth First Search kan word<strong>en</strong> gekarakterizeerd<br />

door e<strong>en</strong> stapel (de eerste buur <strong>van</strong> e<strong>en</strong> knoop wordt ook het eerstvolg<strong>en</strong>d bezocht, waarna di<strong>en</strong>s bur<strong>en</strong> op<br />

de stapel gezet word<strong>en</strong> <strong>en</strong>zovoort) <strong>en</strong> kan dus met e<strong>en</strong> recursieve procedure beschrev<strong>en</strong> word<strong>en</strong>. Breedte<br />

eerst heeft veel meer het karakter <strong>van</strong> e<strong>en</strong> rij. Zo zull<strong>en</strong> we ook deze methode in pseudocode beschrijv<strong>en</strong>.<br />

1: Procedure BFS(Q);<br />

2: if Q �= ∅ th<strong>en</strong><br />

3: remove first elem<strong>en</strong>t v from Q;<br />

4: mark v visited;<br />

5: <strong>en</strong>queue all neighbors of v in Q;<br />

6: BFS(Q);<br />

7: <strong>en</strong>d if<br />

3.2 Kortste pad<strong>en</strong> 3: De A ∗ algoritme<br />

In de AI, met name de robotica, is e<strong>en</strong> algoritme voor het zoek<strong>en</strong> <strong>van</strong> pad<strong>en</strong> in graf<strong>en</strong>, waarbij obstakels<br />

vermed<strong>en</strong> di<strong>en</strong><strong>en</strong> te word<strong>en</strong> zeer populair. Deze algoritme staat teg<strong>en</strong>woordig alom bek<strong>en</strong>d als de A ∗ algoritme.<br />

Het is e<strong>en</strong> variant op Dijkstra’s algoritme die in de praktijk vaak aanzi<strong>en</strong>lijk sneller is, maar in theorie<br />

zelfs niet hoeft te converger<strong>en</strong>. Daarom is deze algoritme in het algoritm<strong>en</strong>onderzoek veel minder bek<strong>en</strong>d<br />

dan in de AI. De algoritme heeft e<strong>en</strong> beetje e<strong>en</strong> merkwaardige naam. In het oorspronkelijke artikel [HNR68]<br />

werd deze algoritme aangeduid met “Algoritme A”. De algoritme is gebaseerd op e<strong>en</strong> techniek die in de AI<br />

“heuristiek”wordt g<strong>en</strong>oemd (zie ook 6.7.3) <strong>en</strong> als e<strong>en</strong> optimale heuristiek in de AI is gevond<strong>en</strong> wordt dat<br />

aangeduid met e<strong>en</strong> ∗, <strong>van</strong>daar de A ∗ algoritme.<br />

In teg<strong>en</strong>stelling tot de algoritme <strong>van</strong> Dijkstra is de A ∗ algoritme er niet per se op gericht het kortste pad<br />

<strong>van</strong> A naar B te vind<strong>en</strong>. Vaak is m<strong>en</strong> al dik tevred<strong>en</strong> als er e<strong>en</strong> pad gevond<strong>en</strong> is. Als de gebruikte heuristiek<br />

bek<strong>en</strong>d is, dan is het vaak ook mogelijk de gebruikte variant <strong>van</strong> de algoritme te verleid<strong>en</strong> e<strong>en</strong> pad langs alle<br />

mogelijke locaties te producer<strong>en</strong>.<br />

60


In overe<strong>en</strong>stemming met de algoritme <strong>van</strong> Dijkstra houdt de A ∗ algoritme e<strong>en</strong> verzameling punt<strong>en</strong> bij<br />

waar<strong>van</strong> het de afstand tot het startpunt A “k<strong>en</strong>t”, dwz e<strong>en</strong> pad <strong>van</strong> A naar dit punt gevond<strong>en</strong> heeft. De<br />

afstand <strong>van</strong> A naar e<strong>en</strong> punt P wordt aangeduid met g(P ). Verder gebruikt de A ∗ algoritme e<strong>en</strong> heuristiek<br />

h die gegev<strong>en</strong> e<strong>en</strong> punt P in de graaf e<strong>en</strong> schatting geeft (vaak e<strong>en</strong> onderschatting) <strong>van</strong> de afstand <strong>van</strong> dat<br />

punt naar het doelpunt B, h(P ). De “verwachte” afstand <strong>van</strong> A tot B is dan de afstand <strong>van</strong> A naar P plus<br />

de afstand <strong>van</strong> P naar B, fP (B) = g(P ) + h(P ). De algoritme maakt dan steeds e<strong>en</strong> update door voor de<br />

knoop mpet minimale fP (B), de bur<strong>en</strong> aan de bek<strong>en</strong>de verzameling toe te voeg<strong>en</strong>, net zo lang tot B aan de<br />

verzameling is toegevoegd.<br />

Voorbeeld 3.2.1: We berek<strong>en</strong><strong>en</strong> de afstand <strong>van</strong> <strong>Amsterdam</strong> naar Eindhov<strong>en</strong> over verschill<strong>en</strong>de tuss<strong>en</strong>stations.<br />

Als heuristiek gebruik<strong>en</strong> we de afstand in c<strong>en</strong>timeters tuss<strong>en</strong> e<strong>en</strong> gegev<strong>en</strong> stad <strong>en</strong> Eindhov<strong>en</strong>,<br />

verm<strong>en</strong>igvuldigd met de schaal <strong>van</strong> de kaart. De tuss<strong>en</strong>stations die we me<strong>en</strong>em<strong>en</strong> zijn: Delft, Utrecht, Ede,<br />

Breda, ’s-Hertog<strong>en</strong>bosch, Nijmeg<strong>en</strong>, Tilburg, <strong>en</strong> Helmond. De werkelijke afstand<strong>en</strong> tuss<strong>en</strong> deze sted<strong>en</strong> over<br />

de weg zijn gegev<strong>en</strong> in de volg<strong>en</strong>de graaf (afgerond overg<strong>en</strong>om<strong>en</strong> <strong>van</strong> e<strong>en</strong> internet routeplanner). De afstand<strong>en</strong><br />

die we (hemelsbreed) <strong>van</strong> de kaart kunn<strong>en</strong> aflez<strong>en</strong> <strong>van</strong> de bur<strong>en</strong> <strong>van</strong> <strong>Amsterdam</strong> naar eindhov<strong>en</strong>,<br />

vermeld<strong>en</strong> we in e<strong>en</strong> tabel ernaast. Deze word<strong>en</strong> gebruikt als schatting voor de rester<strong>en</strong>de afstand.<br />

D<br />

B<br />

T<br />

30<br />

67 46<br />

49<br />

64<br />

101<br />

74<br />

27<br />

35<br />

A<br />

U<br />

S<br />

45<br />

62<br />

46<br />

79<br />

75<br />

67 65<br />

H<br />

Eh<br />

15<br />

D<br />

67<br />

∗<br />

U<br />

��<br />

��<br />

164 120<br />

B<br />

S<br />

��<br />

��<br />

200 141<br />

T<br />

H<br />

E<br />

N<br />

41<br />

E<br />

E<br />

E<br />

��<br />

139<br />

U<br />

stad afstand<br />

Delft 100<br />

Utrecht 75<br />

Ede 60<br />

Breda 54<br />

’s-Hertog<strong>en</strong>bosch 34<br />

Nijmeg<strong>en</strong> 43<br />

Tilburg 30<br />

Helmond 13<br />

��<br />

��<br />

��<br />

��<br />

151 200 188 163<br />

��<br />

��<br />

��<br />

��<br />

��<br />

��<br />

164 187 242 220 198 187<br />

S<br />

61<br />

N<br />

T<br />

H<br />

Eh


Op dit punt is e<strong>en</strong> weg naar Eindhov<strong>en</strong> gevond<strong>en</strong> over Ede <strong>en</strong> Nijmeg<strong>en</strong> met e<strong>en</strong> l<strong>en</strong>gte <strong>van</strong> 187km. De<br />

algoritme kan nu stopp<strong>en</strong>, of prober<strong>en</strong> e<strong>en</strong> kortere weg te vind<strong>en</strong>, want zowel de weg over Delft, als de weg<br />

over Utrecht, ’s-Hertog<strong>en</strong>bosch <strong>en</strong> Tilburg zoud<strong>en</strong> nog korter kunn<strong>en</strong> zijn.<br />

✷<br />

3.3 Netwerk<strong>en</strong> <strong>en</strong> Strom<strong>en</strong><br />

Met graf<strong>en</strong> kunn<strong>en</strong> we <strong>van</strong> alles modeller<strong>en</strong>. Vaak word<strong>en</strong> graf<strong>en</strong> gebruikt om relaties tuss<strong>en</strong> individuele<br />

object<strong>en</strong> te modeller<strong>en</strong>. We zi<strong>en</strong> dan vaak ongerichte graf<strong>en</strong>. Vaak ook word<strong>en</strong> geord<strong>en</strong>de transitieve relaties<br />

gemodelleerd. Pad<strong>en</strong> in de graaf word<strong>en</strong> dan belangrijker dan individuele kant<strong>en</strong>. We beperk<strong>en</strong> de klasse<br />

<strong>van</strong> graf<strong>en</strong> onder beschouwing dan vaak tot gerichte graf<strong>en</strong> (<strong>en</strong> zoud<strong>en</strong> eig<strong>en</strong>lijk ” bog<strong>en</strong>” moet<strong>en</strong> zegg<strong>en</strong> in<br />

plaats <strong>van</strong> kant<strong>en</strong>, maar waar dit niet tot verwarring leidt blijv<strong>en</strong> we toch ook graag in het gerichte geval het<br />

woord ” kant” gebruik<strong>en</strong>). De pad<strong>en</strong> in e<strong>en</strong> gerichte graaf modeller<strong>en</strong> vaak e<strong>en</strong> soort infrastructuur. Zulke<br />

graf<strong>en</strong> zijn het onderwerp <strong>van</strong> deze sectie.<br />

E<strong>en</strong> voorbeeld <strong>van</strong> het gebruik <strong>van</strong> de pad<strong>en</strong> in graf<strong>en</strong> is het probleem <strong>van</strong> de netwerkstrom<strong>en</strong>. We hebb<strong>en</strong><br />

gegev<strong>en</strong> e<strong>en</strong> netwerk dat bestaat uit e<strong>en</strong> graaf <strong>en</strong> twee functies, de capaciteitsfunctie c <strong>en</strong> de stroomfunctie<br />

f. We zull<strong>en</strong> <strong>van</strong> de graaf aannem<strong>en</strong> dat hij gericht is. Dat is ge<strong>en</strong> beperking <strong>van</strong> de algeme<strong>en</strong>heid, want<br />

e<strong>en</strong> weg die in twee richting<strong>en</strong> kan word<strong>en</strong> g<strong>en</strong>om<strong>en</strong>, kan altijd word<strong>en</strong> voorgesteld door e<strong>en</strong> tweetal kant<strong>en</strong>.<br />

Beide functies f <strong>en</strong> c zijn functies <strong>van</strong> de kant<strong>en</strong> naar de reële getall<strong>en</strong> die aan voorwaard<strong>en</strong> verbond<strong>en</strong> zijn.<br />

1. f <strong>en</strong> c zijn allebei groter dan of gelijk aan 0 voor elke kant.<br />

2. Voor elke v geldt � �<br />

e→v f(e) = e←v f(e). Behalve voor twee specifieke knop<strong>en</strong> s <strong>en</strong> t die we de bron<br />

<strong>en</strong> het doel zull<strong>en</strong> noem<strong>en</strong>. Dat wil zegg<strong>en</strong> voor alle knop<strong>en</strong> behalve de bron <strong>en</strong> het doel is de totale<br />

inkom<strong>en</strong>de stroom gelijk aan de totale uitgaande stroom.<br />

3. Voor elke kant e geldt f(e) ≤ c(e).<br />

De capaciteitsfunctie is constant voor het probleem <strong>en</strong> we definier<strong>en</strong> verschill<strong>en</strong>de stroomfuncties. Het<br />

probleem is het vind<strong>en</strong> <strong>van</strong> de stroomfunctie die onder de hierbov<strong>en</strong>beschrev<strong>en</strong> voorwaard<strong>en</strong> de maximale<br />

inkom<strong>en</strong>de stroom in de knoop t geeft. Deze stroom is <strong>van</strong>wege voorwaarde 2 gelijk aan de totale uitgaande<br />

stroom uit s, <strong>en</strong> dit getal zull<strong>en</strong> we (als die bestaat natuurlijk) “de” maximale stroom in het netwerk<br />

noem<strong>en</strong>. We zull<strong>en</strong> e<strong>en</strong> algoritme behandel<strong>en</strong> die de maximale stroom vindt. Eerst zull<strong>en</strong> we bewijz<strong>en</strong> dat<br />

zo’n maximale stroom bestaat.<br />

3.3.1 Min Cut Max Flow<br />

Eerst definier<strong>en</strong> we e<strong>en</strong> doorsnijding <strong>van</strong> het netwerk als e<strong>en</strong> graaf waaruit zoveel kant<strong>en</strong> zijn verwijderd<br />

dat precies twee verbond<strong>en</strong> compon<strong>en</strong>t<strong>en</strong> ontstaan. De <strong>en</strong>e compon<strong>en</strong>t bevat s, <strong>en</strong> de andere compon<strong>en</strong>t<br />

bevat t. Ofwel als G = (V, E), dan is de doorsnijding <strong>van</strong> de graaf de definitie <strong>van</strong> twee verzameling<strong>en</strong><br />

V1, V2 zodat V1 ∪ V2 = V , V1 ∩ V2 = ∅, s ∈ V1, <strong>en</strong> t ∈ V2. De capaciteit <strong>van</strong> e<strong>en</strong> doorsnijding is de<br />

som <strong>van</strong> de capaciteit<strong>en</strong> <strong>van</strong> de kant<strong>en</strong> die <strong>van</strong> de compon<strong>en</strong>t <strong>van</strong> s naar de compon<strong>en</strong>t <strong>van</strong> t lop<strong>en</strong>, ofwel<br />

� {c(e) : e = (v, w) ∧ v ∈ V1, w ∈ V2}.<br />

Stelling 3.3.1 (min-cut-max-flow) De maximale stroom in e<strong>en</strong> netwerk is gelijk aan het minimum g<strong>en</strong>om<strong>en</strong><br />

over de capaciteit<strong>en</strong> <strong>van</strong> alle doorsnijding<strong>en</strong>.<br />

f ≤ min-cut. Allereerst is het duidelijk dat voor elke doorsnijding geldt dat de stroom in het netwerk<br />

kleiner moet zijn dan de capaciteit <strong>van</strong> die doorsnijding. Aangezi<strong>en</strong> er e<strong>en</strong> eindig aantal doorsnijding<strong>en</strong> is,<br />

moet dus zeker geld<strong>en</strong> dat de maximale stroom kleiner dan of gelijk is aan de minimale capaciteit <strong>van</strong> e<strong>en</strong><br />

doorsnijding.<br />

62


f ≥ min-cut. Om in te zi<strong>en</strong> dat in elk netwerk ook e<strong>en</strong> stroom kan lop<strong>en</strong> waar<strong>van</strong> de waarde (= de totale<br />

stroom uit s = de totale stroom in t) gelijk is aan de capaciteit <strong>van</strong> e<strong>en</strong> doorsnijding, <strong>en</strong> <strong>van</strong>wege de vorige<br />

alinea de minimale, gev<strong>en</strong> we e<strong>en</strong> constructief bewijs. Dit ” bewijs” is wat lang <strong>en</strong> eindigt pas op pagina 64,<br />

maar omdat het constructief is, is het nerg<strong>en</strong>s echt ingewikkeld.<br />

We definiër<strong>en</strong> e<strong>en</strong> algoritme die die maximale stroom berek<strong>en</strong>t, <strong>en</strong> bewijz<strong>en</strong> dat de algoritme pas stopt<br />

als die, dan maximale, stroom bereikt is. Deze algoritme is vernoemd naar Ford <strong>en</strong> Fulkerson [FF56], die<br />

deze algorime voor het eerst pres<strong>en</strong>teerd<strong>en</strong>.<br />

De algoritme begint met e<strong>en</strong> stroom 0 door het netwerk <strong>en</strong> zoekt dan zog<strong>en</strong>oemde stroomvergrot<strong>en</strong>de<br />

pad<strong>en</strong>. Dat zijn pad<strong>en</strong> <strong>van</strong> s naar t waardoorhe<strong>en</strong> nog extra stroom “geduwd” kan word<strong>en</strong>. In deze pad<strong>en</strong><br />

word<strong>en</strong> kant<strong>en</strong> in de richting <strong>van</strong> s naar t opg<strong>en</strong>om<strong>en</strong>, maar ook kant<strong>en</strong> in de teg<strong>en</strong>overgestelde richting.<br />

De kant<strong>en</strong> in de richting <strong>van</strong> s naar t kunn<strong>en</strong> in zo’n pad word<strong>en</strong> opg<strong>en</strong>om<strong>en</strong> als de stroom in de graaf<br />

door die kant zijn maximum (capaciteit) nog niet heeft bereikt. Extra stroom door die kant voer<strong>en</strong> zou dan<br />

de stroom langs het pad vergrot<strong>en</strong>, <strong>en</strong> stroom langs e<strong>en</strong> kant in de teg<strong>en</strong>overgestelde richting kan vergroot<br />

word<strong>en</strong>, als de stroom niet gelijk aan nul is. Door die stroom te verklein<strong>en</strong>, vergrot<strong>en</strong> we de stroom langs<br />

het pad. Hebb<strong>en</strong> we zo’n stroomvergrot<strong>en</strong>d pad gevond<strong>en</strong>, dan hebb<strong>en</strong> we voor elke kant apart uitgerek<strong>en</strong>d<br />

hoeveel extra stroom er nog bij zou kunn<strong>en</strong> langs het pad, <strong>en</strong> dan kunn<strong>en</strong> we door het minimum te nem<strong>en</strong><br />

de stroom langs het pad door alle kant<strong>en</strong> berek<strong>en</strong><strong>en</strong>. Het vind<strong>en</strong> <strong>van</strong> e<strong>en</strong> stroomvergrot<strong>en</strong>d pad gaat <strong>van</strong>uit<br />

s met DFS naar t. Als t niet bereikt wordt, dan is de stroom in het netwerk maximaal. We zull<strong>en</strong> e<strong>en</strong><br />

verzameling <strong>van</strong> gemarkeerde knop<strong>en</strong> bijhoud<strong>en</strong> M, met in het begin alle<strong>en</strong> s ∈ M We zull<strong>en</strong> voor kant<strong>en</strong><br />

in de richting <strong>van</strong> het pad het verschil tuss<strong>en</strong> de stroom <strong>en</strong> de capaciteit, <strong>en</strong> voor kant<strong>en</strong> teg<strong>en</strong> de richting<br />

<strong>van</strong> het pad in de stroom zelf de restcapaciteit <strong>van</strong> zo’n kant noem<strong>en</strong>.<br />

1: procedure FFK(node v, real minval)<br />

2: Add v to M;<br />

3: if v = t th<strong>en</strong><br />

4: print(t,minval);<br />

5: return(true);<br />

6: <strong>en</strong>d if<br />

7: for (∀w ∈ V − M)[[(v, w) ∈ E ∧ f((v, w)) < c((v, w))] ∨ [(w, v) ∈ E ∧ f((w, v)) > 0]] do<br />

8: Let p be the residual capacity of this edge.<br />

9: Let q be min{p, minval};<br />

10: if FFK(w, q) th<strong>en</strong><br />

11: print(w);<br />

12: return(true);<br />

13: <strong>en</strong>d if<br />

14: <strong>en</strong>d for<br />

15: return(false);<br />

Deze procedure zoekt met DFS e<strong>en</strong> pad <strong>van</strong> s naar t. Als e<strong>en</strong> pad in t eindigt, dan wordt t sam<strong>en</strong> met<br />

de minimale vergrotingswaarde langs het gevond<strong>en</strong> pad afgedrukt, bov<strong>en</strong>di<strong>en</strong> word<strong>en</strong> omdat de recursieve<br />

aanroep<strong>en</strong> achtere<strong>en</strong>volg<strong>en</strong>s allemaal true terug gev<strong>en</strong> het pad waarlangs de stroom kan word<strong>en</strong> vergroot in<br />

omgekeerde volgorde afgedrukt. Eindigt e<strong>en</strong> pad in e<strong>en</strong> knoop omdat ge<strong>en</strong> vervolgknoop wordt gevond<strong>en</strong>,<br />

dan zal deze knoop ge<strong>en</strong> recursieve aanroep hebb<strong>en</strong> die true teruggeeft <strong>en</strong> dus niet word<strong>en</strong> afgedrukt.<br />

Elke keer dat e<strong>en</strong> stroomvergrot<strong>en</strong>d pad gevond<strong>en</strong> wordt, wordt de stroom met de minimale restcapaciteit<br />

langs dat pad vergroot. Bov<strong>en</strong>di<strong>en</strong> wet<strong>en</strong> we dat de stroom niet de capaciteit <strong>van</strong> <strong>en</strong>ige doorsnijding kan<br />

overstijg<strong>en</strong>. Betek<strong>en</strong>t dat nu dat de maximale stroom ook zal word<strong>en</strong> bereikt door deze algoritme? Helaas<br />

niet. Er bestaan netwerk<strong>en</strong> waarin de restcapaciteit langs stroomvergrot<strong>en</strong>de pad<strong>en</strong> die door deze algoritme<br />

gevond<strong>en</strong> word<strong>en</strong> e<strong>en</strong> machtreeks vorm<strong>en</strong> met e<strong>en</strong> factor kleiner dan 1, <strong>en</strong> waarin de werkelijke maximale<br />

stroom nooit bereikt wordt. Wel kunn<strong>en</strong> we inductief afleid<strong>en</strong> dat als de capaciteit<strong>en</strong> in het netwerk gehele<br />

getall<strong>en</strong> zijn, de stroom steeds met e<strong>en</strong> gehele waarde to<strong>en</strong>eemt. Dat betek<strong>en</strong>t dat het aantal stapp<strong>en</strong> in<br />

e<strong>en</strong> netwerk met geheeltallige capaciteit<strong>en</strong> eindig is. Omdat e<strong>en</strong> getal n in log n bits gerepres<strong>en</strong>teerd kan<br />

word<strong>en</strong> geeft deze observatie echter niet e<strong>en</strong> betere dan expon<strong>en</strong>tiële bov<strong>en</strong>gr<strong>en</strong>s voor de complexiteit <strong>van</strong><br />

het maximaliser<strong>en</strong> <strong>van</strong> de stroom in e<strong>en</strong> netwerk. Ook met geheeltallige capaciteit<strong>en</strong> kan de algoritme <strong>van</strong><br />

63


Ford <strong>en</strong> Fulkerson nog onacceptabel traag kan zijn, getuige het volg<strong>en</strong>de voorbeeld.<br />

Voorbeeld 3.3.1: Beschouw de volg<strong>en</strong>de graaf<br />

◦v ��<br />

◦ s<br />

50<br />

50<br />

1<br />

50<br />

50<br />

��<br />

◦t ��<br />

��<br />

��<br />

◦w E<strong>en</strong> stroomvergrot<strong>en</strong>d pad is, als de stroom 0 is het pad s,v,w,t. Hierlangs kan de stroom met 1 vergroot<br />

word<strong>en</strong>. Daarna is echter het pad s,w,v,t e<strong>en</strong> stroomvergrot<strong>en</strong>d pad geword<strong>en</strong>. Immers de stroom kan<br />

word<strong>en</strong> vergroot door 1 e<strong>en</strong>heid langs dit pad te stur<strong>en</strong>. De stroom <strong>van</strong> v naar w wordt daardoor weer 0.<br />

De algoritme die stroomvergrot<strong>en</strong>de pad<strong>en</strong> vindt zal dus in dit netwerk 50 stapp<strong>en</strong> kunn<strong>en</strong> do<strong>en</strong> voordat de<br />

maximale stroom gevond<strong>en</strong> wordt. Als echter mete<strong>en</strong> de goede pad<strong>en</strong> gekoz<strong>en</strong> word<strong>en</strong>, dan zal de algoritme<br />

slechts twee keer e<strong>en</strong> stroomvergrot<strong>en</strong>d pad hoev<strong>en</strong> te selecter<strong>en</strong>. ✷<br />

De algoritme geeft wel e<strong>en</strong> bewijs voor het tweede onderdeel <strong>van</strong> de min-cut-max-flow stelling, namelijk<br />

e<strong>en</strong> maximale stroom in e<strong>en</strong> netwerk is minst<strong>en</strong>s gelijk aan de minimale capaciteit <strong>van</strong> e<strong>en</strong> doorsnijding.<br />

Stel namelijk maar dat e<strong>en</strong> maximale stroom bereikt is. Er is kan dan ge<strong>en</strong> stroomvergrot<strong>en</strong>d pad meer<br />

word<strong>en</strong> gevond<strong>en</strong>. Dat betek<strong>en</strong>t dat de algoritme t <strong>en</strong> mogelijk e<strong>en</strong> aantal andere knop<strong>en</strong> niet aan M zal<br />

toevoeg<strong>en</strong> in regel 2. Er is dus e<strong>en</strong> doorsnijding te definier<strong>en</strong>, nl. het paar (M, V − M), zo dat v ∈ M, <strong>en</strong><br />

t ∈ V − M. Deze doorsnijding heeft één of andere capaciteit. Er loopt ge<strong>en</strong> kant e <strong>van</strong> M naar V − M<br />

waarvoor f(e) < c(e), noch loopt er e<strong>en</strong> kant e ′ <strong>van</strong> V − M naar M waarvoor f(e ′ ) > 0. Als dit wel het<br />

geval was, dan was M namelijk minst<strong>en</strong>s één knoop groter geweest. Dat wil zegg<strong>en</strong> dat de stroom in het<br />

netwerk t<strong>en</strong>minste gelijk is aan de capaciteit <strong>van</strong> de doorsnijding (M, V − M).<br />

De mogelijke traagheid <strong>van</strong> de Ford-Fulkerson algoritme ligt in het feit dat we onhandig stroomvergrot<strong>en</strong>de<br />

pad<strong>en</strong> kunn<strong>en</strong> kiez<strong>en</strong>. Er is ge<strong>en</strong> duidelijke eig<strong>en</strong>schap <strong>van</strong> het netwerk dat het mogelijk maakt op e<strong>en</strong><br />

handige manier e<strong>en</strong> stroomvergrot<strong>en</strong>d pad te kiez<strong>en</strong>. Wel gev<strong>en</strong> netwerk <strong>en</strong> stroom sam<strong>en</strong> e<strong>en</strong> methode die<br />

het totaal aantal stroomvergrot<strong>en</strong>de pad<strong>en</strong> dat gevond<strong>en</strong> moet word<strong>en</strong> zo klein mogelijk houdt. Netwerk <strong>en</strong><br />

stroom gev<strong>en</strong> namelijk sam<strong>en</strong> e<strong>en</strong> methode om e<strong>en</strong> zog<strong>en</strong>oemd gelaagd netwerk te definiër<strong>en</strong>, <strong>van</strong>waaruit e<strong>en</strong><br />

nieuwe (grotere) stroom gevond<strong>en</strong> kan word<strong>en</strong>. Deze techniek leidt tot maximalisering <strong>van</strong> de stroom in e<strong>en</strong><br />

aantal stapp<strong>en</strong> dat begr<strong>en</strong>sd wordt door e<strong>en</strong> functie <strong>van</strong> het aantal knop<strong>en</strong>. E<strong>en</strong> dramatische verbetering<br />

<strong>van</strong> de complexiteit.<br />

3.3.2 Gelaagde Netwerk<strong>en</strong><br />

Stroomvergrot<strong>en</strong>de pad<strong>en</strong> in e<strong>en</strong> netwerk word<strong>en</strong> gevond<strong>en</strong> door pad<strong>en</strong> <strong>van</strong> s naar t te vind<strong>en</strong>. In die pad<strong>en</strong><br />

nem<strong>en</strong> we kant<strong>en</strong> in de richting <strong>van</strong> s naar t op als er e<strong>en</strong> stroom doorhe<strong>en</strong> loopt die kleiner is dan de<br />

capaciteit. Kant<strong>en</strong> in de richting <strong>van</strong> t naar s word<strong>en</strong> opg<strong>en</strong>om<strong>en</strong> waardoorhe<strong>en</strong> e<strong>en</strong> stroom loopt die groter<br />

is dan 0. In plaats <strong>van</strong> elke keer zo’n kant te kiez<strong>en</strong> <strong>en</strong> met die kant<strong>en</strong> e<strong>en</strong> pad te construer<strong>en</strong>, gev<strong>en</strong> we nu<br />

e<strong>en</strong> methode die als het ware alle stroomvergrot<strong>en</strong>de pad<strong>en</strong> tegelijkertijd vindt.<br />

Laat e<strong>en</strong> netwerk N bestaande uit e<strong>en</strong> graaf G met knop<strong>en</strong> s <strong>en</strong> t, e<strong>en</strong> capaciteitfunctie c <strong>en</strong> e<strong>en</strong> stroomfunctie<br />

f gegev<strong>en</strong> zijn. We definiër<strong>en</strong> inductief het gelaagde netwerk L(N) als volgt.<br />

Laag 0 <strong>van</strong> L(N) bestaat uit de verzameling {s}. Verder bestaat de i + 1ste laag <strong>van</strong> L(N) uit alle<br />

knop<strong>en</strong> w die nog niet zijn opg<strong>en</strong>om<strong>en</strong> in e<strong>en</strong> eerdere laag waarvoor er e<strong>en</strong> knoop v in de i de laag zit met.<br />

1. Er is e<strong>en</strong> kant <strong>van</strong> v naar w met f((v, w)) < c((v, w)), of<br />

2. Er is e<strong>en</strong> kant <strong>van</strong> w naar v met f((v, w)) > 0.<br />

De laatste laag <strong>van</strong> het netwerk bestaat uit de knoop t. Van laag i naar laag i + 1 voeg<strong>en</strong> we steeds de<br />

kant<strong>en</strong> toe die tot opname <strong>van</strong> e<strong>en</strong> knoop in laag i + 1 hebb<strong>en</strong> geleid, met als capaciteit c(e) − f(e) of f(e)<br />

64


afhankelijk <strong>van</strong> de richting waarin de kant in N loopt, totdat we het stadium bereik<strong>en</strong> dat t in één of andere<br />

laag opg<strong>en</strong>om<strong>en</strong> wordt. De knoop t zit altijd alle<strong>en</strong> in de laatste laag <strong>van</strong> het netwerk. Om de constructie<br />

te verduidelijk<strong>en</strong> gev<strong>en</strong> we e<strong>en</strong> klein voorbeeldje. Merk op dat als e<strong>en</strong> knoop v in laag i zit, dat er dan ge<strong>en</strong><br />

kant<strong>en</strong> zijn <strong>van</strong> knoop v <strong>van</strong> of naar knop<strong>en</strong> in laag j < i−1 met de bov<strong>en</strong>beschrev<strong>en</strong> eig<strong>en</strong>schapp<strong>en</strong>. Immers,<br />

als die er wel zoud<strong>en</strong> zijn, dan zou knoop v al opg<strong>en</strong>om<strong>en</strong> zijn in laag j + 1. De hierbeschrev<strong>en</strong> methode<br />

geeft e<strong>en</strong> beschrijving <strong>van</strong> e<strong>en</strong> netwerk waarin altijd nette stroomvergrot<strong>en</strong>de pad<strong>en</strong> lop<strong>en</strong>, die bestaan uit<br />

kant<strong>en</strong> <strong>van</strong> laag i naar laag i + 1.<br />

Voorbeeld 3.3.2: Netwerk<br />

15/37<br />

1<br />

��<br />

20/43<br />

Gelaagd Netwerk<br />

1<br />

22<br />

��<br />

5<br />

23 ��<br />

3<br />

69<br />

56<br />

37<br />

��<br />

2<br />

3<br />

4<br />

40 ��<br />

17<br />

37/93<br />

��<br />

��<br />

8<br />

��<br />

10<br />

��<br />

6<br />

20 �<br />

17/31<br />

75<br />

91<br />

28<br />

25 �<br />

��<br />

� 11<br />

��� 5<br />

��<br />

65<br />

��<br />

6<br />

��<br />

��<br />

��<br />

7<br />

5/45<br />

20/37<br />

37/77<br />

2/3<br />

10/79<br />

10/89<br />

��<br />

����<br />

��<br />

8<br />

��<br />

9<br />

��<br />

��<br />

��<br />

10<br />

10/84<br />

37/84<br />

Als nu de lag<strong>en</strong> <strong>van</strong> het nieuwe netwerk V1, V2, . . . , Vk zijn, dan lop<strong>en</strong> alle stroomvergrot<strong>en</strong>de pad<strong>en</strong> door<br />

ope<strong>en</strong>volg<strong>en</strong>de lag<strong>en</strong>. We kunn<strong>en</strong> nu, beginn<strong>en</strong>d met de kant met minimale capaciteit tuss<strong>en</strong> twee lag<strong>en</strong>, de<br />

stroom vergrot<strong>en</strong> net zolang tot de capaciteit <strong>van</strong> één <strong>van</strong> de doorsnijding<strong>en</strong> bereikt is. We noem<strong>en</strong> zo’n<br />

maximale stroom in e<strong>en</strong> gelaagd netwerk e<strong>en</strong> blokker<strong>en</strong>de stroom <strong>en</strong> we vind<strong>en</strong> zo’n stroom als volgt. Laat de<br />

restcapaciteit <strong>van</strong> e<strong>en</strong> knoop het minimum zijn <strong>van</strong> de som <strong>van</strong> de restcapaciteit<strong>en</strong> <strong>van</strong> zijn uitgaande kant<strong>en</strong><br />

<strong>en</strong> de som <strong>van</strong> de restcapaciteit<strong>en</strong> <strong>van</strong> de ingaande kant<strong>en</strong>. We zoek<strong>en</strong> de knoop met minimale restcapaciteit,<br />

<strong>en</strong> voeg<strong>en</strong> deze capaciteit eerst toe als stroom aan de uitgaande kant<strong>en</strong> <strong>van</strong> de knoop. Vervolg<strong>en</strong>s duw<strong>en</strong> we<br />

deze stroom door het netwerk als volgt. Eerst zorg<strong>en</strong> we ervoor dat in lag<strong>en</strong> hoger dan de laag waarin deze<br />

knoop zit de behoudswett<strong>en</strong> weer geld<strong>en</strong>, <strong>en</strong> daarna zorg<strong>en</strong> we ervoor dat ook in de lag<strong>en</strong> lager dan de laag<br />

waarin deze knoop zit de behoudswett<strong>en</strong> weer gaan geld<strong>en</strong>. We beginn<strong>en</strong> met deze knoop <strong>en</strong> zijn ingaande<br />

kant<strong>en</strong>. Minimaal één knoop in het gelaagde netwerk is nu verzadigd. We hal<strong>en</strong> deze knoop met met al zijn<br />

ingaande <strong>en</strong> uitgaande kant<strong>en</strong> uit het netwerk <strong>en</strong> pass<strong>en</strong> de stroom aan zodat de behoudswett<strong>en</strong> weer geld<strong>en</strong>.<br />

Als er nog e<strong>en</strong> stroomvergrot<strong>en</strong>d pad <strong>van</strong> s naar t is, dan herhal<strong>en</strong> we de procedure, anders hebb<strong>en</strong> we e<strong>en</strong><br />

blokker<strong>en</strong>de stroom gevond<strong>en</strong>.<br />

De blokker<strong>en</strong>de stroom kan nu word<strong>en</strong> opgeteld bij de stroom in het netwerk <strong>en</strong> e<strong>en</strong> nieuw gelaagd<br />

65<br />

8/63<br />

52/80<br />

25/25<br />

��<br />

11<br />

��<br />


netwerk kan word<strong>en</strong> berek<strong>en</strong>d. E<strong>en</strong> nieuw gelaagd netwerk kan niet al te vaak word<strong>en</strong> berek<strong>en</strong>d. We kunn<strong>en</strong><br />

bewijz<strong>en</strong> dat elk nieuw gelaagd netwerk dat wordt berek<strong>en</strong>d na e<strong>en</strong> nieuwe, blokker<strong>en</strong>de stroom, bij de<br />

stroom te hebb<strong>en</strong> opgeteld t<strong>en</strong>minste één laag dieper is dan het vorige. Aangezi<strong>en</strong> er hoogst<strong>en</strong>s V knop<strong>en</strong><br />

zijn, betek<strong>en</strong>t dit dat t<strong>en</strong> hoogste V zulke fas<strong>en</strong> in de volg<strong>en</strong>de algoritme zitt<strong>en</strong>.<br />

1: repeat<br />

2: compute layered network Y = LN(N, f);<br />

3: if t ∈ Y th<strong>en</strong> compute blocking flow in Y ;<br />

4: else<br />

5: write flow at maximum; exit<br />

6: <strong>en</strong>d if<br />

7: add blocking flow to f<br />

8: until exit occurs<br />

In ons voorbeeld gelaagde netwerk is eerst knoop 5 de knoop met de kleinste capaciteit (22). Na aanpassing<br />

<strong>van</strong> het netwerk <strong>en</strong> verwijdering <strong>van</strong> knoop 5, is knoop 8 de knoop met de kleinste capaciteit (6).<br />

Als knoop 8 verwijderd is, is er ge<strong>en</strong> pad meer <strong>van</strong> s naar t. We kunn<strong>en</strong> in totaal 28 e<strong>en</strong>hed<strong>en</strong> bij de<br />

stroom optell<strong>en</strong> <strong>en</strong> e<strong>en</strong> nieuw gelaagd netwerk berek<strong>en</strong><strong>en</strong>. De algoritme die e<strong>en</strong> maximale stroom vindt met<br />

behulp <strong>van</strong> blokker<strong>en</strong>de netwerk<strong>en</strong> wordt MKM algoritme g<strong>en</strong>oemd, naar de bed<strong>en</strong>kers Malhotra, Kumar <strong>en</strong><br />

Maheshwari [MKM78].<br />

3.4 Toepassing<strong>en</strong> <strong>van</strong> Network Flow<br />

De algoritm<strong>en</strong> die we besprok<strong>en</strong> hebb<strong>en</strong> voor het maximaliser<strong>en</strong> <strong>van</strong> de stroom kunn<strong>en</strong> we gebruik<strong>en</strong> om<br />

andere problem<strong>en</strong> op te loss<strong>en</strong>. Veel toepassing<strong>en</strong> zijn d<strong>en</strong>kbaar, we noem<strong>en</strong> er hier drie.<br />

3.4.1 Perfect Matching<br />

Als eerste voorbeeld bekijk<strong>en</strong> we het probleem PERFECT MATCHING, dat we ook verderop in deze tekst in<br />

e<strong>en</strong> wat ingewikkelder vorm teg<strong>en</strong> zull<strong>en</strong> kom<strong>en</strong>. Gegev<strong>en</strong> is e<strong>en</strong> ongerichte tweedelige graaf G = ((V1, V2), E)<br />

<strong>en</strong> gevraagd is e<strong>en</strong> deelverzameling <strong>van</strong> de kant<strong>en</strong> te vind<strong>en</strong>, zo dat elke knoop in het <strong>en</strong>e deel <strong>van</strong> de graaf<br />

verbond<strong>en</strong> is met precies één knoop in het andere deel <strong>van</strong> de graaf. Dit probleem is met het maximaliser<strong>en</strong><br />

<strong>van</strong> strom<strong>en</strong> op te loss<strong>en</strong> als volgt. Geef alle kant<strong>en</strong> in G e<strong>en</strong> richting zodat ze <strong>van</strong> V1 naar V2 lop<strong>en</strong>. Voeg<br />

aan V twee knop<strong>en</strong> s <strong>en</strong> t toe. Verbind s met alle knop<strong>en</strong> uit V1, <strong>en</strong> t met alle knop<strong>en</strong> uit V2, waarbij de<br />

nieuwe kant<strong>en</strong> uit s <strong>en</strong> in t gericht zijn. T<strong>en</strong>slotte krijg<strong>en</strong> alle kant<strong>en</strong> capaciteit 1. We kunn<strong>en</strong> nu bewijz<strong>en</strong><br />

dat zowel de Ford-Fulkerson algoritme als de gelaagde netwerk algoritme e<strong>en</strong> maximale stroom vindt waarbij<br />

elke kant stroom 1 of 0 heeft, <strong>en</strong> dat door elke knoop in V1 <strong>en</strong> V2 precies één <strong>en</strong>heid stroom gaat. Immers,<br />

de restcapaciteit bij elke update <strong>van</strong> de flow algoritme is steeds e<strong>en</strong> geheel getal <strong>en</strong> de totale inkom<strong>en</strong>de<br />

capaciteit <strong>van</strong> elke knoop in V1 is 1 terwijl de totale uitgaande capaciteit <strong>van</strong> e<strong>en</strong> knoop in V2 ev<strong>en</strong>e<strong>en</strong>s 1 is.<br />

Als we nu alle kant<strong>en</strong> tuss<strong>en</strong> V1 <strong>en</strong> V2 selecter<strong>en</strong> waarlangs e<strong>en</strong> stroom 1 loopt, dan hebb<strong>en</strong> we e<strong>en</strong> perfecte<br />

matching gevond<strong>en</strong>.<br />

3.4.2 Connectivity<br />

E<strong>en</strong> belangrijk probleem dat sam<strong>en</strong>hangt met het al eerder besprok<strong>en</strong> probleem <strong>van</strong> het vind<strong>en</strong> <strong>van</strong> articulation<br />

points is het vind<strong>en</strong> <strong>van</strong> de connectiviteit <strong>van</strong> e<strong>en</strong> graaf. De connectiviteit <strong>van</strong> e<strong>en</strong> graaf is het<br />

minimum aantal kant<strong>en</strong> dat verwijderd moet word<strong>en</strong> om t<strong>en</strong>minste twee compon<strong>en</strong>t<strong>en</strong> over te houd<strong>en</strong>. Dit<br />

probleem kunn<strong>en</strong> we [ET75] oploss<strong>en</strong> met de algoritme voor het maximaliser<strong>en</strong> <strong>van</strong> de stroom in e<strong>en</strong> netwerk,<br />

als volgt. Laat e<strong>en</strong> graaf G = (V, E) gegev<strong>en</strong> zijn. We mak<strong>en</strong> netwerk N = (V, E, f) door 1 als source te<br />

gebruik<strong>en</strong> <strong>en</strong> e<strong>en</strong> willekeurige knoop j als sink. Vervolg<strong>en</strong>s ver<strong>van</strong>g<strong>en</strong> we elk paar (v, w) ∈ E door e<strong>en</strong> kant<br />

in beide richting<strong>en</strong> die allebei capaciteit 1 hebb<strong>en</strong> <strong>en</strong> berek<strong>en</strong><strong>en</strong> e<strong>en</strong> maximale stroom Fj. Het maximum <strong>van</strong><br />

de getall<strong>en</strong> F1, . . . , Fn is de edge connectivity <strong>van</strong> G.<br />

66


3.4.3 Matrixsomm<strong>en</strong><br />

De laatste toepassing <strong>van</strong> strom<strong>en</strong> in netwerk<strong>en</strong> die we besprek<strong>en</strong> is het probleem <strong>van</strong> de matrixsomm<strong>en</strong>.<br />

naam: Matrix Som<br />

gegev<strong>en</strong>: Twee verzameling<strong>en</strong> getall<strong>en</strong> R <strong>en</strong> C<br />

gevraagd: Is het mogelijk e<strong>en</strong> 0/1 matrix op te stell<strong>en</strong> zodat de getall<strong>en</strong> in R precies de rijsomm<strong>en</strong> zijn<br />

<strong>en</strong> de getall<strong>en</strong> in C precies de kolomsomm<strong>en</strong> zijn?<br />

Ook dit probleem kan met netwerk flow word<strong>en</strong> opgelost. Stel maar dat de rijsomm<strong>en</strong> r1, . . . , rm zijn<br />

<strong>en</strong> de kolomsomm<strong>en</strong> s1, . . . , sn. We mak<strong>en</strong> e<strong>en</strong> netwerk N als volgt. De knoop s is verbond<strong>en</strong> met knop<strong>en</strong><br />

x1, . . . , xn door kant<strong>en</strong> met capaciteit r1, . . . , rn respectievelijk, <strong>en</strong> de <strong>van</strong>uit de knop<strong>en</strong> y1, . . . , ym lop<strong>en</strong><br />

kant<strong>en</strong> met capaciteit s1, . . . , sm respectievelijk naar t. Verder loopt <strong>van</strong> elke xi e<strong>en</strong> kant naar elke yj met<br />

capaciteit 1. Maximaliseer de stroom <strong>en</strong> zet e<strong>en</strong> 1 op plaats (i, j) in de matrix als in de maximale stroom<br />

de stroom door de corresponder<strong>en</strong>de kant 1 is.<br />

3.4.4 Somm<strong>en</strong><br />

1. Bewijs dat e<strong>en</strong> graaf met n knop<strong>en</strong> <strong>en</strong> meer dan n − 1 kant<strong>en</strong> e<strong>en</strong> cykel heeft.<br />

2. Kijk naar de volg<strong>en</strong>de algoritme voor ongerichte graf<strong>en</strong> G = (V, E).<br />

1: repeat<br />

2: Find nodes v, v ′ such that there is no path from v to v ′ ;<br />

3: Add (v, v ′ ) to E;<br />

4: until no such pair can be found<br />

Als |V | = n, dan is de scherpste afschatting voor het aantal ker<strong>en</strong> dat de repeat loop wordt uitgevoerd<br />

O( √ n), O(n), O(n 2 ) of O(n 3 )? Waarom?<br />

3. n > 1 person<strong>en</strong> staan op e<strong>en</strong> veld, gewap<strong>en</strong>d met e<strong>en</strong> taart. Iedere<strong>en</strong> heeft e<strong>en</strong> unieke dichtstbijstaande<br />

buur die met 100% zekerheid geraakt wordt, <strong>en</strong> iedere<strong>en</strong> gooit tegelijkertijd. Als iemand niet geraakt<br />

wordt noem<strong>en</strong> we die persoon ” overlev<strong>en</strong>de”.<br />

(a) Geef e<strong>en</strong> voorbeeld waarbij er ge<strong>en</strong> overlev<strong>en</strong>d<strong>en</strong> zijn, <strong>en</strong> e<strong>en</strong> voorbeeld waarbij er meer dan één<br />

overlev<strong>en</strong>de is.<br />

(b) Laat zi<strong>en</strong> dat voor onev<strong>en</strong> n er altijd minst<strong>en</strong>s één overlev<strong>en</strong>de is.<br />

4. E<strong>en</strong> gerichte acyclische graaf is e<strong>en</strong> tralie als hij e<strong>en</strong> knoop s heeft, zodat <strong>van</strong> s naar elke andere knoop<br />

in de graaf e<strong>en</strong> pad loopt <strong>en</strong> e<strong>en</strong> knoop t, zodat <strong>van</strong>uit elke andere knoop in de graaf e<strong>en</strong> pad naar t<br />

loopt.<br />

(a) Beschrijf e<strong>en</strong> algoritme die voor e<strong>en</strong> input gerichte acyclische graaf beslist of het e<strong>en</strong> tralie is.<br />

(b) Wat is de worst-case looptijd <strong>van</strong> de algoritme?<br />

(c) Gegev<strong>en</strong> e<strong>en</strong> graaf met gewog<strong>en</strong> kant<strong>en</strong>. Laat A ∗ algoritme gebruik mak<strong>en</strong> <strong>van</strong> de heuristiek h,<br />

die de afstand <strong>van</strong> twee punt<strong>en</strong> op het papier waarop de graaf getek<strong>en</strong>d is berek<strong>en</strong>t. Bed<strong>en</strong>k e<strong>en</strong><br />

graaf met twee punt<strong>en</strong> A <strong>en</strong> B zo dat de algoritme e<strong>en</strong> pad tuss<strong>en</strong> A <strong>en</strong> B produceert dat langs<br />

alle punt<strong>en</strong> gaat, <strong>en</strong> niet het optimale pad is.<br />

5. E<strong>en</strong> toernooi (ook wel volledige gerichte graaf g<strong>en</strong>oemd) is e<strong>en</strong> graaf waarbij elk tweetal punt<strong>en</strong> door<br />

e<strong>en</strong> kant verbond<strong>en</strong> wordt. E<strong>en</strong> kampio<strong>en</strong> in e<strong>en</strong> toernooi is e<strong>en</strong> punt dat afstand hoogst<strong>en</strong>s twee tot<br />

elk ander punt heeft. Dwz. k is e<strong>en</strong> kampio<strong>en</strong> als voor elke x in het toernooi er ofwel e<strong>en</strong> kant <strong>van</strong> k<br />

naar x is ofwel er e<strong>en</strong> y in het toernooi is, zo dat er e<strong>en</strong> kant <strong>van</strong> k naar y <strong>en</strong> e<strong>en</strong> kant <strong>van</strong> y naar x<br />

bestaat. Bewijs (met inductie) dat elk toernooi e<strong>en</strong> kampio<strong>en</strong> heeft. Is zo’n kampio<strong>en</strong> uniek?<br />

6. Bewijs met inductie dat in e<strong>en</strong> netwerk met geheeltallige capaciteit<strong>en</strong>, de algoritme <strong>van</strong> Ford <strong>en</strong> Fulkerson<br />

altijd convergeert.<br />

67


7. Laat zi<strong>en</strong> dat er netwerk<strong>en</strong> bestaan waarin de algoritme <strong>van</strong> Ford <strong>en</strong> Fulkerson niet convergeert.<br />

8. Bewijs dat na de berek<strong>en</strong>ing <strong>van</strong> e<strong>en</strong> blokker<strong>en</strong>de stroom <strong>en</strong> aanpassing <strong>van</strong> de stroom in het originele<br />

netwerk het nieuwe gelaagde netwerk altijd t<strong>en</strong>minste één laag dieper is.<br />

9. Het probleem System of Distinct Repres<strong>en</strong>tatives (SDR) wordt als volgt gedefinieerd.<br />

naam: SDR<br />

gegev<strong>en</strong>: E<strong>en</strong> collectie deelverzameling<strong>en</strong> {Si} m i=1 <strong>van</strong> e<strong>en</strong> verzameling U = {u1, . . . , un}<br />

gevraagd: Bestaat er e<strong>en</strong> S ′ = {u ′ 1, . . . , u ′ m}, zó dat u ′ i ∈ Si <strong>en</strong> u ′ i �= u′ j voor i �= j?<br />

Geef e<strong>en</strong> algoritme voor dit probleem m.b.v. netwerkstrom<strong>en</strong>.<br />

10. E<strong>en</strong> stel families gaan sam<strong>en</strong> uit et<strong>en</strong>. Om de sociale interactie te vergrot<strong>en</strong> will<strong>en</strong> ze e<strong>en</strong> tafelarrangem<strong>en</strong>t<br />

bed<strong>en</strong>k<strong>en</strong> zo dat ge<strong>en</strong> twee led<strong>en</strong> <strong>van</strong> dezelfde familie aan dezelfde tafel zitt<strong>en</strong>. Stel dat er p<br />

families zijn <strong>en</strong> dat de i-de familie a(i) led<strong>en</strong> heeft. Stel ook dat er q tafels beschikbaar zijn <strong>en</strong> dat de<br />

j-de tafel capaciteit q(j) heeft. Formuleer dit probleem als e<strong>en</strong> network-flow probleem.<br />

programmer<strong>en</strong><br />

1. E<strong>en</strong> reisbureau heeft over de hele wereld 1000 vestiging<strong>en</strong>, die tegelijkertijd toegang hebb<strong>en</strong> tot e<strong>en</strong><br />

gedistribueerd databasesysteem om plaats<strong>en</strong> op bepaalde vlucht<strong>en</strong> te reserver<strong>en</strong>. De plaats<strong>en</strong> zijn<br />

aangegev<strong>en</strong> alle<strong>en</strong> door stoelnummers, maar e<strong>en</strong> stoelnummer kan natuurlijk ook de vlucht waar<strong>van</strong> zij<br />

deel uitmaakt id<strong>en</strong>tificer<strong>en</strong>. Als reservering<strong>en</strong> verschill<strong>en</strong>de stoelnummers betreff<strong>en</strong>, kan de database<br />

ze tegelijkertijd (in één batch) vastlegg<strong>en</strong>, maar sommige vlucht<strong>en</strong> zijn populairder dan andere, <strong>en</strong><br />

dus komt het vaak voor dat twee of meer reservering<strong>en</strong> voor hetzelfde stoelnummer gemaakt moet<strong>en</strong><br />

word<strong>en</strong>. Die moet<strong>en</strong> dan in volgorde <strong>van</strong> binn<strong>en</strong>komst word<strong>en</strong> afgehandeld. Implem<strong>en</strong>teer e<strong>en</strong> batch<br />

<strong>van</strong> 100000 aanvrag<strong>en</strong>, waarbij stoelnummers random tuss<strong>en</strong> de 1 <strong>en</strong> de 500 word<strong>en</strong> gekoz<strong>en</strong>. Het<br />

programma moet e<strong>en</strong> verdeling mak<strong>en</strong> <strong>van</strong> de transacties zo dat zo min mogelijk batches voorkom<strong>en</strong>.<br />

2. Stel e<strong>en</strong>s dat ons reisbureau alle<strong>en</strong> maar <strong>van</strong> par<strong>en</strong> transacties kan vaststell<strong>en</strong> dat ze niet gelijktijdig<br />

gedraaid kunn<strong>en</strong> word<strong>en</strong>. Dus niet per se omdat ze dezelfde stoel will<strong>en</strong> reserver<strong>en</strong> maar bijvoorbeeld<br />

omdat ze e<strong>en</strong> printer in hetzelfde kantoor will<strong>en</strong> gebruik<strong>en</strong>, dezelfde vluchttabel will<strong>en</strong> raadpleg<strong>en</strong><br />

of wat dan ook. Nu kan dus alle<strong>en</strong> <strong>van</strong> twee transacties T1 <strong>en</strong> T2 word<strong>en</strong> vastgesteld dat ze niet<br />

tegelijkertijd uitgevoerd kunn<strong>en</strong> word<strong>en</strong>, maar niet noodzakelijk <strong>van</strong> grotere verzameling<strong>en</strong>. Hoe pak<br />

je nu het probleem aan?<br />

3. Maak e<strong>en</strong> netwerk <strong>van</strong> ongeveer 100 knop<strong>en</strong> met willekeurige capaciteit<strong>en</strong> tuss<strong>en</strong> de 1 <strong>en</strong> de 100.<br />

Vergelijk op dit netwerk de snelhed<strong>en</strong> <strong>van</strong> de Ford-Fulkerson algoritme <strong>en</strong> de MKM algoritme.<br />

68


Hoofdstuk 4<br />

Numerieke <strong>Algoritm<strong>en</strong></strong><br />

4.1 De Euclidische Algoritme <strong>en</strong> Uitbreiding<strong>en</strong><br />

Het wordt wel ” de oudste algoritme” g<strong>en</strong>oemd, de algoritme om de grootste gem<strong>en</strong>e deler <strong>van</strong> twee getall<strong>en</strong><br />

te bepal<strong>en</strong>. Voor het eerst beschrev<strong>en</strong> in ” Elem<strong>en</strong>t<strong>en</strong>” <strong>van</strong> Euclides, ongeveer 300 voor Christus <strong>en</strong> oorspronkelijk<br />

geformuleerd als e<strong>en</strong> meetkundig probleem: zoek e<strong>en</strong> geme<strong>en</strong>schappelijke maat voor twee lijnstukk<strong>en</strong>.<br />

Deze algoritme echter was bijna zeker al 200 jaar eerder bek<strong>en</strong>d bij Eudoxus <strong>van</strong> Cnidus (375vChr) <strong>en</strong> ook<br />

Aristoteles verwijst er in 330 vChr al naar in zijn Topica. De algoritme die wij k<strong>en</strong>n<strong>en</strong> als ” de Euclidische<br />

Algoritme” is dus waarschijnlijk net zo min <strong>van</strong> Euclides als de ” Stelling <strong>van</strong> Pythagoras”<strong>van</strong> Pythagoras<br />

was (het is bek<strong>en</strong>d dat deze stelling door Pythagoras gestol<strong>en</strong> is <strong>van</strong> de Babyloniers). Niettemin zull<strong>en</strong><br />

wij de algoritme uit deze sectie ” de Euclidische Algoritme noem<strong>en</strong>” <strong>en</strong> de pas veel later bek<strong>en</strong>d geword<strong>en</strong><br />

uitbreiding die we nodig hebb<strong>en</strong> in Sectie 4.5 als de ” Uitgebreide Euclidische Algoritme”. Waar ging het<br />

ook alweer over? Als we twee getall<strong>en</strong> a <strong>en</strong> b hebb<strong>en</strong>, dan is er e<strong>en</strong> grootste getal dat beide getall<strong>en</strong> deelt.<br />

Als dat getal 1 is, dan zegg<strong>en</strong> we dat a <strong>en</strong> b relatief priem zijn, anders kunn<strong>en</strong> wij e<strong>en</strong> groter getal dan 1<br />

vind<strong>en</strong> dat beide getall<strong>en</strong> deelt, maar hoe? We zoud<strong>en</strong> bijvoorbeeld de beide getall<strong>en</strong> kunn<strong>en</strong> ontbind<strong>en</strong> in<br />

(priem)factor<strong>en</strong>, <strong>en</strong> dan de kleinste macht<strong>en</strong> <strong>van</strong> de geme<strong>en</strong>schappelijke priemfactor<strong>en</strong> kunn<strong>en</strong> uitverm<strong>en</strong>igvuldig<strong>en</strong>.<br />

Bijvoorbeeld 1400 = 2 3 · 5 2 · 7 <strong>en</strong> 6860 = 2 2 · 5 · 7 3 , waaruit volgt dat de grootste gem<strong>en</strong>e deler <strong>van</strong><br />

1400 <strong>en</strong> 6860 gelijk is aan 2 2 · 5 · 7 = 140. Dat geeft zeker de grootste gem<strong>en</strong>e deler, maar is, zeker voor grote<br />

getall<strong>en</strong>, e<strong>en</strong> moeizaam proces. Veel simpeler is de algoritme gebaseerd op de volg<strong>en</strong>de observatie. Als je<br />

twee getall<strong>en</strong> a <strong>en</strong> b hebt <strong>en</strong> a = qb + t, dan deelt elk getal dat zowel t als b deelt ook a. De grootste gem<strong>en</strong>e<br />

deler <strong>van</strong> t <strong>en</strong> b is dus ook de grootste gem<strong>en</strong>e deler <strong>van</strong> a <strong>en</strong> b. Als b = 0, dan is a de grootste gem<strong>en</strong>e deler<br />

<strong>van</strong> a <strong>en</strong> b, want elk getal deelt 0. Dit suggereert e<strong>en</strong> recursieve algoritme: óf één <strong>van</strong> a <strong>en</strong> b is 0 <strong>en</strong> dan is<br />

het klaar, óf a > b <strong>en</strong> dan schrijv<strong>en</strong> we a = qb + t met t zo klein mogelijk <strong>en</strong> gaan verder met b <strong>en</strong> t. We<br />

schrijv<strong>en</strong> dit in pseudocode in Figuur 4.1<br />

1: r = a mod b<br />

2: while r �= 0 do<br />

3: a = b<br />

4: b = r<br />

5: r = a mod b<br />

6: <strong>en</strong>d while<br />

Figuur 4.1: grootste gem<strong>en</strong>e deler<br />

Als r gelijk aan 0 is geword<strong>en</strong>, dan is b gelijk geword<strong>en</strong> aan de grootste gem<strong>en</strong>e deler <strong>van</strong> de oorspronkelijke<br />

getall<strong>en</strong>. Deze algoritme is aanzi<strong>en</strong>lijk efficiënter dan het ontbind<strong>en</strong> in factor<strong>en</strong>. Aangezi<strong>en</strong> in elke iteratie<br />

de getall<strong>en</strong> minst<strong>en</strong>s door 2 gedeeld word<strong>en</strong> kan de loop niet vaker dan log keer doorlop<strong>en</strong> word<strong>en</strong>, in het<br />

aantal bits <strong>van</strong> de input is dat dus lineair. Hierbij nem<strong>en</strong> we echter aan dat elke deling één stap kost, wat<br />

69


ij grote getall<strong>en</strong> misschi<strong>en</strong> niet e<strong>en</strong> reële aanname is.<br />

4.1.1 De Uitgebreide Euclidische Algoritme <strong>en</strong> Invers<strong>en</strong><br />

Neem twee getall<strong>en</strong> a > b. Als de grootste gem<strong>en</strong>e deler <strong>van</strong> a <strong>en</strong> b gelijk is aan 1, dan heeft b e<strong>en</strong><br />

multiplicatieve inverse modulo a, ofwel, er is e<strong>en</strong> getal x zodanig dat bx mod a = ggd(a, b) = 1. Dit getal x<br />

kan bij het bepal<strong>en</strong> <strong>van</strong> de grootste gem<strong>en</strong>e deler <strong>van</strong> a <strong>en</strong> b door de Euclidische algoritme gevond<strong>en</strong> word<strong>en</strong>.<br />

Dat gaat als volgt.<br />

De Euclidische algoritme is gebaseerd op de waarneming dat de grootste gem<strong>en</strong>e deler <strong>van</strong> twee getall<strong>en</strong><br />

a <strong>en</strong> b gelijk is aan de grootste gem<strong>en</strong>e deler <strong>van</strong> b <strong>en</strong> a mod b, ofwel als a = qb + r <strong>en</strong> r = a mod b,<br />

dan geldt d = ggd(a, b) = ggd(b, r). Stel nu e<strong>en</strong>s dat de recursieve algoritme gebaseerd op deze observatie<br />

niet alle<strong>en</strong> de ggd terug zou gev<strong>en</strong> maar ook twee getall<strong>en</strong> k <strong>en</strong> l zodat d = kb + lr. Dan hebb<strong>en</strong> we dat<br />

d = kb + lr = kb + l(a − qb) = la + (k − lq)b <strong>en</strong> dus d = xa + yb. Als d gelijk is aan 1 <strong>en</strong> we rek<strong>en</strong><strong>en</strong> modulo<br />

a, dan staat daar 1 = (k − lq)b. Het probleem is alle<strong>en</strong>, dat we de grootste gem<strong>en</strong>e deler pas op de bodem<br />

<strong>van</strong> de recursie teg<strong>en</strong> kom<strong>en</strong>. Op de bodem <strong>van</strong> de recursie staat echter altijd b = 0 dus hier kunn<strong>en</strong> we e<strong>en</strong><br />

standaard antwoord gev<strong>en</strong>, namelijk a is de ggd <strong>en</strong> k = 1 <strong>en</strong> l = 0.<br />

1: function Egcd(a, b)<br />

2: if b = 0 th<strong>en</strong><br />

3: return (a,1,0)<br />

4: else<br />

5: r = a mod b;<br />

6: q = (a − r)/b;<br />

7: (d, k, l) = Egcd(b, r);<br />

8: return(d, l, k − lq);<br />

9: <strong>en</strong>d if<br />

Figuur 4.2: de uitgebreide Euclidische algoritme<br />

Voorbeeld 4.1.1: E<strong>en</strong> getall<strong>en</strong>voorbeeld is altijd illustratief. We berek<strong>en</strong><strong>en</strong> dus de inverse <strong>van</strong> 17 modulo<br />

93 met deze algoritme. We beginn<strong>en</strong> met het uitvoer<strong>en</strong> <strong>van</strong> de uitgebreide Euclidische algoritme.<br />

a = q × b + r<br />

93 = 5 × 17 + 8<br />

17 = 2 × 8 + 1<br />

De volg<strong>en</strong>de stap is 0. De vergelijking<strong>en</strong> d = kb + lr = kb + l(a − qb) = la + (k − lq)b vertell<strong>en</strong> nu<br />

achtere<strong>en</strong>volg<strong>en</strong>s 1 = 1 × 17 − 2 × 8, 1 = 1 × 17 − 2 × (93 − 5 × 17), <strong>en</strong> 1 = −2 × 93 + 11 × 17, waaruit volgt<br />

dat 11 de inverse <strong>van</strong> 17 modulo 93 is.<br />

Dus d = 1 = 11 × 17 − 2 × 93 waaruit volgt dat 11 het gezochte getal is. ✷<br />

Het resultaat <strong>van</strong> deze algoritme is e<strong>en</strong> getal l dat modulo b de multiplicatieve inverse is <strong>van</strong> a (uiteraard<br />

alle<strong>en</strong> als de grootste gem<strong>en</strong>e deler <strong>van</strong> a <strong>en</strong> b gelijk is aan 1).<br />

4.1.2 somm<strong>en</strong><br />

1. Schrijf e<strong>en</strong> niet-recursieve versie <strong>van</strong> de Euclidische algoritme. G<strong>en</strong>eraliseer dit tot e<strong>en</strong> niet-recursieve<br />

versie <strong>van</strong> de uitgebreide Euclidische algoritme.<br />

2. Bewijs het bestaan <strong>van</strong> additieve invers<strong>en</strong> in Zp. Dat wil zegg<strong>en</strong> laat zi<strong>en</strong> dat er voor elke x ∈ Zp e<strong>en</strong><br />

y ∈ Zp bestaat zó dat x + y mod p = 0.<br />

3. Maak e<strong>en</strong> verm<strong>en</strong>igvuldigingstabel voor Z5, waar het elem<strong>en</strong>t op plaats (i, j) in de tabel gelijk is aan<br />

i ∗ j mod 5.<br />

70


4. Berek<strong>en</strong> de multiplicatieve invers<strong>en</strong> <strong>van</strong> de getall<strong>en</strong> 435, 234, <strong>en</strong> 534 in Z947.<br />

4.2 Verm<strong>en</strong>igvuldiging <strong>van</strong> Grote Getall<strong>en</strong>, DFT<br />

4.2.1 Inleiding<br />

Computers zijn rek<strong>en</strong>automat<strong>en</strong> <strong>en</strong> rek<strong>en</strong><strong>en</strong>, naast zoek<strong>en</strong> <strong>en</strong> sorter<strong>en</strong>, is nog steeds hun belangrijkste activiteit.<br />

Van de rek<strong>en</strong>kundige operaties: optell<strong>en</strong>, aftrekk<strong>en</strong>, verm<strong>en</strong>igvuldig<strong>en</strong>, del<strong>en</strong>, machtsverheff<strong>en</strong> <strong>en</strong><br />

worteltrekk<strong>en</strong> word<strong>en</strong> sommige veel vaker uitgevoerd dan andere, <strong>en</strong> zijn sommige complexer, dwz. vereis<strong>en</strong><br />

meer rek<strong>en</strong>kracht dan andere.<br />

In veel gevall<strong>en</strong> beschouw<strong>en</strong> we e<strong>en</strong> optelling of verm<strong>en</strong>igvuldiging als e<strong>en</strong> atomaire operatie, <strong>en</strong> tell<strong>en</strong><br />

voor elke verm<strong>en</strong>igvuldiging één stap. Dat is niet altijd gerechtvaardigd, zie ook 5.2.2. Omdat machines<br />

beperkte registergrootte hebb<strong>en</strong> (meestal 8, 16, 32 of 64 bits), kan e<strong>en</strong> verm<strong>en</strong>igvuldiging <strong>van</strong> twee willekeurig<br />

grote getall<strong>en</strong> niet in één stap word<strong>en</strong> uitgevoerd, maar moet<strong>en</strong> del<strong>en</strong> <strong>van</strong> de getall<strong>en</strong> (vaak individuele<br />

cijfers) net zoals wanneer je met de hand <strong>en</strong> kladpapier verm<strong>en</strong>igvuldigt, apart word<strong>en</strong> uitgevoerd. Het<br />

resultaat <strong>van</strong> de verm<strong>en</strong>igvuldiging volgt dan vaak uit e<strong>en</strong> optelling <strong>van</strong> de tuss<strong>en</strong>resultat<strong>en</strong>. In deze sectie<br />

zull<strong>en</strong> we verschill<strong>en</strong>de verm<strong>en</strong>igvuldingsalgoritm<strong>en</strong> bekijk<strong>en</strong>, beginn<strong>en</strong>d met één die we ook voor verm<strong>en</strong>igvuldiging<br />

met de hand gebruik<strong>en</strong>, <strong>en</strong> de complexiteit <strong>van</strong> deze algoritm<strong>en</strong> analyser<strong>en</strong>. Zoals we gew<strong>en</strong>d zijn,<br />

gaan we voorbij aan constante factor<strong>en</strong> in de complexiteit, maar de lezer zij bijvoorbaat gewaarschuwd dat<br />

in de algoritm<strong>en</strong> die in deze sectie gepres<strong>en</strong>teerd word<strong>en</strong> deze factor<strong>en</strong> wel degelijk e<strong>en</strong> rol spel<strong>en</strong>. De meest<br />

efficiënte algoritme voor verm<strong>en</strong>igvuldiging, die aan het eind gepres<strong>en</strong>teerd wordt, is daarom alle<strong>en</strong> zinvol<br />

bij het verm<strong>en</strong>igvuldig<strong>en</strong> <strong>van</strong> zeer grote getall<strong>en</strong>—<strong>en</strong>kele honderd<strong>en</strong> cijfers. Gelukkig heeft het verm<strong>en</strong>igvuldig<strong>en</strong><br />

<strong>van</strong> zeer grote getall<strong>en</strong> teg<strong>en</strong>woordig toepassing gevond<strong>en</strong> in de cryptografie, zoals we verderop in dit<br />

hoofdstuk zull<strong>en</strong> zi<strong>en</strong>. Public key cryptosystem<strong>en</strong> mak<strong>en</strong> gebruik <strong>van</strong> sleutels die het resultaat zijn <strong>van</strong> de<br />

verm<strong>en</strong>igvuldiging <strong>van</strong> priemgetall<strong>en</strong> <strong>van</strong> <strong>en</strong>kele honderd<strong>en</strong> cijfers. Om e<strong>en</strong> boodschap te coder<strong>en</strong>, wordt e<strong>en</strong><br />

getal dat de boodschap in binaire code voorstelt tot de macht zo’n groot getal g<strong>en</strong>om<strong>en</strong>. Hiervoor zijn dus<br />

meerdere verm<strong>en</strong>igvuldiging<strong>en</strong> met grote getall<strong>en</strong> nodig, ev<strong>en</strong>als e<strong>en</strong> effici<strong>en</strong>te manier <strong>van</strong> machtsverheff<strong>en</strong>.<br />

Hierop kom<strong>en</strong> we later terug.<br />

4.2.2 De eerste algoritm<strong>en</strong><br />

De algoritme voor verm<strong>en</strong>igvuldiging die m<strong>en</strong>s<strong>en</strong> het meest gebruik<strong>en</strong> is het ” vierkante schema” dat we op<br />

de basisschool ler<strong>en</strong>. Stel dat we de getall<strong>en</strong> 981 <strong>en</strong> 1234 will<strong>en</strong> verm<strong>en</strong>igvuldig<strong>en</strong>. Dan schrijv<strong>en</strong> we deze<br />

getall<strong>en</strong> onder elkaar als.<br />

981<br />

1234<br />

3924<br />

29430<br />

196200<br />

981000<br />

1210554<br />

Overig<strong>en</strong>s zij opgemerkt dat dit cultuurbepaald is. Op de Engelse schol<strong>en</strong> wordt dit verm<strong>en</strong>igvuldigingsschema<br />

” andersom” geleerd als:<br />

981<br />

1234<br />

981000<br />

196200<br />

29430<br />

3942<br />

1210554<br />

71


Hoeveel elem<strong>en</strong>taire operaties (verm<strong>en</strong>igvuldiging <strong>van</strong> twee ééncijfergetall<strong>en</strong>) kost dit? Als we e<strong>en</strong> getal<br />

<strong>van</strong> n cijfers met e<strong>en</strong> getal <strong>van</strong> m cijfers verm<strong>en</strong>igvuldig<strong>en</strong>, dan kunn<strong>en</strong> we in het vierkant <strong>van</strong> verm<strong>en</strong>igvuldiging<br />

hierbov<strong>en</strong> zi<strong>en</strong> dat er n × m verm<strong>en</strong>igvuldiging<strong>en</strong> <strong>van</strong> ééncijfergetall<strong>en</strong> gedaan word<strong>en</strong>. Dit is niet<br />

optimaal.<br />

4.3 Betere algoritm<strong>en</strong> voor verm<strong>en</strong>igvuldiging<br />

E<strong>en</strong> andere manier om 2 getall<strong>en</strong> met elkaar te verm<strong>en</strong>igvuldig<strong>en</strong> wordt gegev<strong>en</strong> door het onderstaande<br />

schema.<br />

981 1234 1234<br />

490 2468<br />

245 4936 4936<br />

122 9872<br />

61 19744 19744<br />

30 39488<br />

15 78976 78976<br />

7 157952 157952<br />

3 315904 315904<br />

1 631808 631808<br />

1210554<br />

Het maakt gebruik <strong>van</strong> de simpele observatie dat je twee operand<strong>en</strong> met elkaar kunt verm<strong>en</strong>igvuldig<strong>en</strong><br />

door de <strong>en</strong>e operand herhaald te halver<strong>en</strong> terwijl de andere herhaald verdubbeld wordt. Daarbij moet, omdat<br />

naar b<strong>en</strong>ed<strong>en</strong> wordt afgerond wel op de onev<strong>en</strong> deling<strong>en</strong> gelet word<strong>en</strong>. Daarom word<strong>en</strong> in de meest rechtse<br />

kolom alle getall<strong>en</strong> waarbij de linkerkolom onev<strong>en</strong> wordt, bij elkaar opgeteld om het eindresultaat te krijg<strong>en</strong>.<br />

Enige analyse leert dat deze algoritme nog steeds n 2 bewerking<strong>en</strong> doet om twee getall<strong>en</strong> <strong>van</strong> n cijfers met<br />

elkaar te verm<strong>en</strong>igvuldig<strong>en</strong>. Voor computers heeft deze verm<strong>en</strong>igvuldiging ” à la russe” zoals hij g<strong>en</strong>oemd<br />

wordt echter e<strong>en</strong> zeer groot voordeel. Het betreft alle<strong>en</strong> verm<strong>en</strong>igvuldig<strong>en</strong> met <strong>en</strong> del<strong>en</strong> door 2. In machines<br />

is dat e<strong>en</strong> simpele shift operatie.<br />

E<strong>en</strong> zeer populaire manier om algoritm<strong>en</strong> te ontwikkel<strong>en</strong> is de ” verdeel-<strong>en</strong>-heersmethode” (zie Sectie 2.2).<br />

Het probleem wordt uitgedrukt in twee of meer kleinere deelproblem<strong>en</strong> die dan vervolg<strong>en</strong>s word<strong>en</strong> opgelost<br />

door ze weer in kleinere problem<strong>en</strong> te verdel<strong>en</strong>. Op de ” bodem” <strong>van</strong> deze aanpak ligt het oploss<strong>en</strong> <strong>van</strong><br />

problem<strong>en</strong> <strong>van</strong> grootte 1 of kleiner. Die problem<strong>en</strong> k<strong>en</strong>n<strong>en</strong> e<strong>en</strong> triviale oplossing.<br />

We kunn<strong>en</strong> deze methode natuurlijk ook toepass<strong>en</strong> op verm<strong>en</strong>igvuldiging<strong>en</strong>. De bodem <strong>van</strong> de verm<strong>en</strong>igvuldiging<br />

is immers het verm<strong>en</strong>igvuldig<strong>en</strong> <strong>van</strong> individuele cijfers. Hiervoor hebb<strong>en</strong> wij op de bassisschool<br />

tabell<strong>en</strong> (tafels) geleerd, dus dat kost ge<strong>en</strong> inspanning. In ons voorbeeld ziet dat er (op het één na laagste<br />

niveau) zo uit:<br />

verm<strong>en</strong>igvuldig schuif resultaat<br />

i) 09 12 4 1080000<br />

ii) 09 34 2 30600<br />

iii) 81 12 2 97200<br />

iv) 81 34 0 2754<br />

1210554<br />

We merk<strong>en</strong> hier op dat we e<strong>en</strong> truuk kunn<strong>en</strong> toepass<strong>en</strong> analoog aan de truuk die door Strass<strong>en</strong> is<br />

ontwikkeld voor matrixverm<strong>en</strong>igvuldiging (zie 2.2.1). Het verm<strong>en</strong>igvuldig<strong>en</strong> <strong>van</strong> 2 getall<strong>en</strong> <strong>van</strong> 4 cijfers kost<br />

namelijk op deze manier 4 verm<strong>en</strong>igvuldiging<strong>en</strong> <strong>van</strong> getall<strong>en</strong> <strong>van</strong> 2 cijfers (de schuifoperaties daargelat<strong>en</strong>)<br />

72


als:<br />

34 × 81 = 2754<br />

12 × 81 × 100 = 97200<br />

34 × 09 × 100 = 30600<br />

12 × 09 × 10000 = 1080000<br />

1210554<br />

Bijgevolg kost het verm<strong>en</strong>igvuldig<strong>en</strong> <strong>van</strong> twee getall<strong>en</strong> <strong>van</strong> n cijfers op deze manier 4 log2n = n log 2 4 = n 2 ,<br />

dus in complexiteit winn<strong>en</strong> we weer niets. Echter met het volg<strong>en</strong>de schema kunn<strong>en</strong> de vier verm<strong>en</strong>igvuldiging<strong>en</strong><br />

ver<strong>van</strong>g<strong>en</strong> word<strong>en</strong> door drie verm<strong>en</strong>igvuldiging<strong>en</strong>: (a × 100 + b)(c × 100 + d) = a × c × 100 × 100 +<br />

b × c × 100 + a × d × 100 + b × d. Echter b × c + a × d = (a + b)(c + d) − ac − bd. Dus als we (a + b)(c + d),<br />

ac, <strong>en</strong> bd uitrek<strong>en</strong><strong>en</strong>, hebb<strong>en</strong> we alles wat we nodig hebb<strong>en</strong> (in drie verm<strong>en</strong>igvuldiging<strong>en</strong>). In getall<strong>en</strong>:<br />

<strong>en</strong><br />

<strong>en</strong><br />

09 × 12 = 108<br />

81 × 34 = 2754<br />

(09 + 81)(12 + 34) = 90 × 46 = 4140<br />

981 × 1234 = 1080000 + (4140 − 108 − 2754) × 100 + 2754 = 1210554<br />

waardoor de complexiteit daalt tot n log23 verm<strong>en</strong>igvuldiging<strong>en</strong>. Het is ge<strong>en</strong> grote winst, maar in geval<br />

miljo<strong>en</strong><strong>en</strong> <strong>van</strong> deze verm<strong>en</strong>igvuldiging<strong>en</strong> moet<strong>en</strong> word<strong>en</strong> gedaan, of heel grote getall<strong>en</strong> met elkaar verm<strong>en</strong>igvuldigd<br />

moet<strong>en</strong> word<strong>en</strong>, zeker de moeite waard.<br />

4.3.1 De kampio<strong>en</strong><br />

In deze sectie zull<strong>en</strong> we e<strong>en</strong> algoritme pres<strong>en</strong>ter<strong>en</strong> die vooralsnog als de snelste algoritme voor de verm<strong>en</strong>igvuldiging<br />

wordt beschouwd. De algoritme is gebaseerd op de Fast Fourier transformatie, in de vorige eeuw<br />

bedacht door Cooley <strong>en</strong> Tukey.<br />

4.3.2 Getall<strong>en</strong> als polynom<strong>en</strong><br />

Kijk naar het getal 10230495. We kunn<strong>en</strong> het schrijv<strong>en</strong> als<br />

1 × 10 7 + 0 × 10 6 + 2 × 10 5 + 3 × 10 4 + 0 × 10 3 + 4 × 10 2 + 9 × 10 1 + 5.<br />

Elk getal <strong>van</strong> n cijfers is e<strong>en</strong> polynoom <strong>van</strong> de graad n − 1 uitgerek<strong>en</strong>d in het punt 10. In plaats <strong>van</strong> te<br />

onderzoek<strong>en</strong> hoe duur het verm<strong>en</strong>igvuldig<strong>en</strong> <strong>van</strong> getall<strong>en</strong> is, zoud<strong>en</strong> we dus de algem<strong>en</strong>ere vraag kunn<strong>en</strong><br />

stell<strong>en</strong>: ” Hoe duur is het verm<strong>en</strong>igvuldig<strong>en</strong> <strong>van</strong> twee polynom<strong>en</strong>, <strong>en</strong> hoe duur is het uitrek<strong>en</strong><strong>en</strong> <strong>van</strong> e<strong>en</strong><br />

polynoom in e<strong>en</strong> punt?”<br />

We merk<strong>en</strong> eerst op dat e<strong>en</strong> polynoom <strong>van</strong> de graad n − 1 geheel bepaald is als we de waard<strong>en</strong> <strong>van</strong> het<br />

polynoom in n punt<strong>en</strong> wet<strong>en</strong>. E<strong>en</strong> lijn (eerstegraadspolynoom) ligt vast als we er twee punt<strong>en</strong> <strong>van</strong> k<strong>en</strong>n<strong>en</strong>,<br />

<strong>en</strong> e<strong>en</strong> parabool ligt vast als we er drie punt<strong>en</strong> <strong>van</strong> k<strong>en</strong>n<strong>en</strong>, immers het invull<strong>en</strong> <strong>van</strong> drie waard<strong>en</strong> voor x <strong>en</strong><br />

y in e<strong>en</strong> vergelijking <strong>van</strong> de vorm y = ax 2 + bx + c geeft drie lineaire vergelijking<strong>en</strong> met drie onbek<strong>en</strong>d<strong>en</strong>.<br />

Algem<strong>en</strong>er: het invull<strong>en</strong> <strong>van</strong> n punt<strong>en</strong> in e<strong>en</strong> vergelijking y = an−1x n−1 + an−2x n−2 + . . . + a0 geeft n<br />

vergelijking<strong>en</strong> met n onbek<strong>en</strong>d<strong>en</strong> <strong>en</strong> dus hoogst<strong>en</strong>s 1 oplossing voor an−1, . . . , a0.<br />

Dus, als we n + m − 1 punt<strong>en</strong> <strong>van</strong> e<strong>en</strong> polynoom wet<strong>en</strong> dat het product is <strong>van</strong> e<strong>en</strong> polynoom <strong>van</strong> de<br />

graad n − 1 <strong>en</strong> e<strong>en</strong> polynoom <strong>van</strong> de graad m − 1 dan ligt dat polynoom, omdat het <strong>van</strong> de graad hoogst<strong>en</strong>s<br />

n − 1 + m − 1 is, daarmee vast. Wanneer we echter voor e<strong>en</strong> x de waarde <strong>van</strong> e<strong>en</strong> polynoom p1 in dat punt<br />

wet<strong>en</strong> <strong>en</strong> we wet<strong>en</strong> de waarde <strong>van</strong> e<strong>en</strong> polynoom p2 in dat punt, dan is het heel gemakkelijk te achterhal<strong>en</strong><br />

wat de waarde <strong>van</strong> e<strong>en</strong> polynoom p1 × p2 in dat punt is. Verm<strong>en</strong>igvuldig namelijk alle<strong>en</strong> die waard<strong>en</strong> met<br />

elkaar.<br />

73


Figuur 4.3: x 2 + x + 1, x 3 − 2x − 1, <strong>en</strong> (x 2 + x + 1)(x 3 − 2x − 1)<br />

Als we dus n + m − 1 punt<strong>en</strong> <strong>van</strong> p1 hebb<strong>en</strong> <strong>en</strong> n + m − 1 punt<strong>en</strong> <strong>van</strong> p2 in dezelfde rij x-waard<strong>en</strong>, dan<br />

krijg<strong>en</strong> we met n + m − 1 verm<strong>en</strong>igvuldiging<strong>en</strong> e<strong>en</strong> verzameling punt<strong>en</strong> die het productpolynoom volledig<br />

vastlegg<strong>en</strong>.<br />

Voorbeeld 4.3.1: In Figuur 4.3 zi<strong>en</strong> we de grafiek<strong>en</strong> <strong>van</strong> x 2 + x + 1 <strong>en</strong> x 3 − 2x − 1. Het product <strong>van</strong> deze<br />

polynom<strong>en</strong> is e<strong>en</strong> vijfdegraads polynoom. Om dit polynoom vast te legg<strong>en</strong> hebb<strong>en</strong> we zes punt<strong>en</strong> nodig.<br />

x x 2 + x + 1 x 3 − 2x − 1 ×<br />

−3 7 −22 −154<br />

−2 3 −5 −15<br />

−1 1 0 0<br />

0 1 −1 −1<br />

1 3 −2 −6<br />

2 7 3 21<br />

E<strong>en</strong> vijfdegraadspolynoom ziet eruit als ax 5 + bx 4 + cx 3 + dx 2 + ex + f. Om het productpolynoom te<br />

bepal<strong>en</strong> moet<strong>en</strong> we dus de volg<strong>en</strong>de vergelijking<strong>en</strong> oploss<strong>en</strong>:<br />

−243a + 81b − 27c + 9d − 3e + f = −154<br />

−32a + 16b − 8c + 4d − 2e + f = −15<br />

−a + b − c + d − e + f = 0<br />

f = −1<br />

a + b + c + d + e + f = −6<br />

32a + 16b + 8c + 4d + 2e + f = 21<br />

Loss<strong>en</strong> we deze vergelijking<strong>en</strong> op, dan vind<strong>en</strong> we a = 1, b = 1,c = −1, d = −3, e = −3, <strong>en</strong> f = −1. Het<br />

productpolynoom wordt dus<br />

x 5 + x 4 − x 3 − 3x 2 − 3x − 1.<br />

De algoritme voor polynoomverm<strong>en</strong>igvuldiging: ” rek<strong>en</strong> de polynom<strong>en</strong> uit in n + m − 1 punt<strong>en</strong> → rek<strong>en</strong><br />

de punt<strong>en</strong> <strong>van</strong> het productpolynoom uit → vertaal de punt<strong>en</strong> terug naar coëffici<strong>en</strong>t<strong>en</strong>” dringt zich op. De<br />

vraag is alle<strong>en</strong>: hoe duur zijn de buit<strong>en</strong>ste vertaalslag<strong>en</strong>?<br />

74<br />


Voor het uitrek<strong>en</strong><strong>en</strong> <strong>van</strong> polynom<strong>en</strong> in punt<strong>en</strong> zijn verschill<strong>en</strong>de algoritm<strong>en</strong> bek<strong>en</strong>d, bijvoorbeeld x 5 +<br />

2x 4 + 3x 3 + x 2 + x + 1 in 2 als 2 5 + 2 · 2 4 + 3 · 2 3 + 2 2 + 2 + 1 of ((((2 + 2)2 + 3)2 + 1)2 + 1)2 + 1. De snelste<br />

algoritm<strong>en</strong> gev<strong>en</strong> echter toch ongeveer n verm<strong>en</strong>igvuldiging<strong>en</strong> voor één punt. Dat betek<strong>en</strong>t voor n + m − 1<br />

punt<strong>en</strong> nog steeds kwadratische complexiteit. We moet<strong>en</strong> zoek<strong>en</strong> naar e<strong>en</strong> methode waarbij we de evaluatie<br />

<strong>van</strong> polynom<strong>en</strong> in n punt<strong>en</strong> tegelijkertijd kunn<strong>en</strong> do<strong>en</strong> voor minder dan O(n 2 ) operaties. Dat vereist e<strong>en</strong><br />

stel punt<strong>en</strong> met speciale eig<strong>en</strong>schapp<strong>en</strong>. Zo’n stel punt<strong>en</strong> is de verzameling <strong>van</strong> de complexe n-de machts<br />

e<strong>en</strong>heidswortels.<br />

4.3.3 Complexe n-de machts e<strong>en</strong>heidswortels<br />

De complexe n-de machts e<strong>en</strong>heidswortels zijn de oplossing<strong>en</strong> <strong>van</strong> de vergelijking x n − 1 = 0. In de reële<br />

getall<strong>en</strong> heeft deze vergelijking hoogst<strong>en</strong>s 2 oplossing<strong>en</strong>, namelijk 1 <strong>en</strong> −1 <strong>en</strong> dan alle<strong>en</strong> nog voor ev<strong>en</strong><br />

waard<strong>en</strong> <strong>van</strong> n. Lat<strong>en</strong> wij echter complexe getall<strong>en</strong> toe <strong>van</strong> de vorm a + bi, waarbij a <strong>en</strong> b reële getall<strong>en</strong> zijn<br />

<strong>en</strong> i e<strong>en</strong> getal met de eig<strong>en</strong>schap i 2 = −1, dan heeft de vergelijking plotseling n oplossing<strong>en</strong>.<br />

In 1.4.3 zag<strong>en</strong> we de reeks<strong>en</strong> voor sinus, cosinus <strong>en</strong> e-macht<strong>en</strong>:<br />

e x = � ∞<br />

m=0 xm /m!<br />

sin x = � ∞<br />

r=0 (−1)r x 2r+1 /(2r + 1)!<br />

cos x = � ∞<br />

r=0 (−1)r x 2r /(2r)!<br />

log 1<br />

1−x = � ∞<br />

j+1 xj /j<br />

Lat<strong>en</strong> we het zojuist gedefinieerde getal i e<strong>en</strong>s gebruik<strong>en</strong> <strong>en</strong> e<strong>en</strong>s invull<strong>en</strong> ix invull<strong>en</strong> in de reeks<strong>en</strong> voor sin<br />

<strong>en</strong> cos. We zi<strong>en</strong> dat cos x+i sin x = �∞ r=0 (−1)rx2r /(2r)!+i �∞ r=0 (−1)rx2r+1 /(2r +1)! = �∞ m=0 (ix)m /m! =<br />

e ix .<br />

Vanwege de periodiciteit <strong>van</strong> sin <strong>en</strong> cos geldt nu dus voor elke n <strong>en</strong> 0 < j < n dat (e 2πij/n ) n =<br />

cos 2jπ + i sin 2jπ = 1. Voor elke n zijn de n verschill<strong>en</strong>de getall<strong>en</strong> ω j(n) = e i2πj/n = cos 2πj/n + i sin 2πj/n<br />

de n verschill<strong>en</strong>de oplossing<strong>en</strong> <strong>van</strong> de vergelijking x n − 1 = 0. We noem<strong>en</strong> deze getall<strong>en</strong> de complexe n-de<br />

machts e<strong>en</strong>heidswortels <strong>en</strong> deze getall<strong>en</strong> hebb<strong>en</strong> e<strong>en</strong> aantal interessante eig<strong>en</strong>schapp<strong>en</strong>. Als n er niet to doet<br />

lat<strong>en</strong> we n vaak weg uit de notatie <strong>en</strong> schrijv<strong>en</strong> we ωj.<br />

Laat ω = ω1 = e 2πi/n , dan is ωj = ω j .<br />

1. ω n−1<br />

j<br />

= ω−1 j<br />

2. Voor n > 1: � n−1<br />

k=0 ωk j<br />

want ωn−1 j × ωj = ωn j<br />

= 0 want<br />

�<br />

= 1.<br />

n−1<br />

ω k j = ωn j<br />

k=0<br />

− 1<br />

ωj − 1<br />

= 1 − 1<br />

ωj − 1 =<br />

3. als ωj e<strong>en</strong> 2n-de machts e<strong>en</strong>heidswortel is, dan is ω2 j<br />

(ω2 j )n = 1.<br />

4. Voor ev<strong>en</strong> n > 0 geldt ω n/2 = −1 want<br />

n−1 �<br />

0 =<br />

k=0<br />

4.3.4 De Fast-Fourier transform<br />

0<br />

= 0.<br />

ωj − 1<br />

e<strong>en</strong> n-de machts e<strong>en</strong>heidswortel, want ω2n<br />

j<br />

ω (n/2)k = ω 0 + ω n/2 + . . . + ω 0 + ω n/2 = (n/2)(1 + ω n/2 )<br />

Precies deze eig<strong>en</strong>schapp<strong>en</strong> gev<strong>en</strong> g<strong>en</strong>oeg voor het snel evaluer<strong>en</strong> <strong>van</strong> polynom<strong>en</strong> in n punt<strong>en</strong>. We nem<strong>en</strong><br />

voor het gemak aan dat n e<strong>en</strong> macht <strong>van</strong> 2 is. Dat is ge<strong>en</strong> beperking <strong>van</strong> de algeme<strong>en</strong>heid, want als n ge<strong>en</strong><br />

tweemacht is, dan ligt er e<strong>en</strong> tweemacht dicht bij n (kleiner dan n × 2 <strong>en</strong> we kunn<strong>en</strong> e<strong>en</strong> polynoom altijd<br />

uitbreid<strong>en</strong> tot zijn graad e<strong>en</strong> tweemacht is (door 0-coëffici<strong>en</strong>t<strong>en</strong> op te nem<strong>en</strong>). Beschouw nu het polynoom<br />

p = an−1x n−1 + . . . + a0. We kunn<strong>en</strong> p onderverdel<strong>en</strong> in e<strong>en</strong> ev<strong>en</strong> polynoom pe <strong>en</strong> e<strong>en</strong> onev<strong>en</strong> polynoom po<br />

75<br />

=


als pe = an−2x n−2 + . . . + a0 <strong>en</strong> po = an−1x n−1 + . . . + a1x. Verder is po = x(an−1x n−2 + . . . + a1). We<br />

gebruik<strong>en</strong> nu de eig<strong>en</strong>schap 3 uit het rijtje eig<strong>en</strong>schapp<strong>en</strong> <strong>en</strong> merk<strong>en</strong> op dat het evaluer<strong>en</strong> <strong>van</strong> e<strong>en</strong> polynoom<br />

in e<strong>en</strong> n de machts e<strong>en</strong>heidswortel kan word<strong>en</strong> gedaan t<strong>en</strong> koste <strong>van</strong> de evaluatie <strong>van</strong> dat polynoom in e<strong>en</strong><br />

n/2-de machts e<strong>en</strong>heidswortel plus één verm<strong>en</strong>igvuldiging, <strong>en</strong> dat deze eig<strong>en</strong>schap recursief is.<br />

Dit betek<strong>en</strong>t dat we de evaluatie <strong>van</strong> de polynom<strong>en</strong> kunn<strong>en</strong> uitstell<strong>en</strong> totdat er niet zoveel e<strong>en</strong>heidswortels<br />

zijn (bijvoorbeeld 1) <strong>en</strong> dan vervolg<strong>en</strong>s de evaluatie <strong>van</strong> de polynom<strong>en</strong> daar kunn<strong>en</strong> gebruik<strong>en</strong> om hogerop<br />

de evaluatie <strong>van</strong> grotere polynom<strong>en</strong> in t<strong>en</strong> koste <strong>van</strong> 1 verm<strong>en</strong>igvuldiging te krijg<strong>en</strong>. De algoritme is dan als<br />

volgt.<br />

Voor evaluatie <strong>van</strong> e<strong>en</strong> polynoom <strong>van</strong> graad n−1 in de n-de machts e<strong>en</strong>heidswortels. Evalueer pe <strong>en</strong> po in<br />

alle n/2 de machts e<strong>en</strong>heidswortels <strong>en</strong> doe telk<strong>en</strong>s 1 extra verm<strong>en</strong>igvuldiging. Probleem is dat er natuurlijk<br />

maar half zoveel n/2e machts e<strong>en</strong>heidswortels zijn als n-de machts e<strong>en</strong>heidswortels, maar dat probleem wordt<br />

opgelost door de periodiciteit <strong>van</strong> de laatste. In het volg<strong>en</strong>de voorbeeld licht<strong>en</strong> we dat toe.<br />

Voorbeeld 4.3.2: Stel we evaluer<strong>en</strong> het vijfde graads polynoom<br />

2x 5 + 2x 4 + 4x 3 + 2x 2 + 8x + 1<br />

in de achtste macht éénheidswortels <strong>en</strong> we zijn bij de berek<strong>en</strong>ing bij ω5 = e 2πi5/8 . We splits<strong>en</strong> het polynoom<br />

in<br />

pe = 2x 4 + 2x 2 + 1<br />

<strong>en</strong><br />

Invull<strong>en</strong> geeft<br />

<strong>en</strong><br />

We zi<strong>en</strong> dat<br />

<strong>en</strong><br />

po = 2x 5 + 4x 3 + 8x = x(2x 4 + 4x 2 + 8).<br />

pe(e 2πi5/8 ) = 2(e 2πi5/8 ) 4 + 2(e 2πi5/8 ) 2 + 1<br />

po(e 2πi5/8 ) = (e 2πi5/8 )(2(e 2πi5/8 ) 4 + 4(e 2πi5/8 ) 2 + 8).<br />

pe(e 2πi5/8 ) = 2(e 2πi5/4 ) 2 + 2(e 2πi5/4 ) + 1<br />

po(e 2πi5/8 ) = (e 2πi5/8 )(2(e 2πi5/4 ) 2 + 4(e 2πi5/4 ) + 8).<br />

We zi<strong>en</strong> dus dat we de vierdemachts éénheidswortels nodig hebb<strong>en</strong>, ware het niet dat er ge<strong>en</strong> vijfde vierdemachts<br />

e<strong>en</strong>heidswortel bestaat. Gelukkig is echter e 2πi5/4 = e 2πi1/4 <strong>van</strong>wege de periodiciteit <strong>van</strong> de<br />

éénheidswortels. ✷<br />

De complexiteit <strong>van</strong> de hierbov<strong>en</strong>beschrev<strong>en</strong> algoritme is telk<strong>en</strong>s n verm<strong>en</strong>igvuldiging<strong>en</strong> plus de kost<strong>en</strong><br />

<strong>van</strong> de evaluatie <strong>van</strong> de polynom<strong>en</strong> <strong>van</strong> de halve l<strong>en</strong>gte. Waarbij het evaluer<strong>en</strong> <strong>van</strong> e<strong>en</strong> polynoom <strong>van</strong><br />

de graad 0 in alle 1 de machts e<strong>en</strong>heidswortels uiteraard als e<strong>en</strong>heidsstap gerek<strong>en</strong>d mag word<strong>en</strong>. In e<strong>en</strong><br />

recurr<strong>en</strong>te betrekking: T (n) = n + 2T (n/2). De oplossing <strong>van</strong> deze betrekking is T (n) = O(n log n).<br />

4.3.5 De inverse Fourier transform<br />

We zijn nu halverwege. We kunn<strong>en</strong> de beide polynom<strong>en</strong> voor de prijs <strong>van</strong> n log n verm<strong>en</strong>igvuldiging<strong>en</strong> op n<br />

punt<strong>en</strong> evaluer<strong>en</strong>, <strong>en</strong> dan t<strong>en</strong> koste <strong>van</strong> n verm<strong>en</strong>igvuldiging<strong>en</strong> met elkaar verm<strong>en</strong>igvuldig<strong>en</strong> om n punt<strong>en</strong><br />

<strong>van</strong> het productopolynoom in hand<strong>en</strong> te krijg<strong>en</strong>. Dan moet<strong>en</strong> we echter terug. Gelukkig is de terugweg<br />

net zo e<strong>en</strong>voudig als de he<strong>en</strong>weg. We bewer<strong>en</strong> dat we de coëffici<strong>en</strong>t<strong>en</strong> <strong>van</strong> het productpolynoom in hand<strong>en</strong><br />

kunn<strong>en</strong> krijg<strong>en</strong> door dezelfde algoritme toe te pass<strong>en</strong>, maar nu met de verkreg<strong>en</strong> punt<strong>en</strong> als coëffici<strong>en</strong>t<strong>en</strong>, <strong>en</strong><br />

de evaluatie <strong>van</strong> de polynom<strong>en</strong> in de punt<strong>en</strong> ω −1<br />

j . Om dat in te zi<strong>en</strong> beschouw<strong>en</strong> we de Fourier transformatie<br />

als matrixverm<strong>en</strong>igvuldiging. In Figuur 4.4 zi<strong>en</strong> we de matrix <strong>van</strong> de Fouriertransformatie <strong>en</strong> de inverse <strong>van</strong><br />

die matrix onder elkaar.<br />

Immers<br />

76


(F −1 × F )[i, j] = 1 �n−1 n k=0 ωk i<br />

De <strong>en</strong>tries <strong>van</strong> deze matrix zijn 1<br />

Dit is � 1<br />

⎛<br />

⎜<br />

F × a = ⎜<br />

⎝ .<br />

F −1 = 1<br />

n<br />

1 1 · · · 1<br />

1 ω1 · · · ω n−1<br />

1<br />

.<br />

1 ωn−1 · · · ω n−1<br />

n−1<br />

.<br />

.<br />

⎞ ⎛<br />

⎟ ⎜<br />

⎟ ⎜<br />

⎟ ⎜<br />

⎠ ⎝<br />

⎛<br />

1 1 · · · 1<br />

⎜<br />

⎝ . . . .<br />

1 ω −1<br />

1 · · · (ω −1<br />

1 )n−1<br />

1 ω −1<br />

n−1 · · · (ω −1<br />

n−1 )n−1<br />

a0<br />

a1<br />

.<br />

an−1<br />

⎞<br />

⎟<br />

⎠ .<br />

Figuur 4.4: De Fourier transformatie <strong>en</strong> inverse<br />

× (ω−1 j ) k .<br />

n<br />

� n−1<br />

k=0 (ωi × (ω −1<br />

i )) k<br />

⎞<br />

⎟<br />

⎠<br />

�n−1 n k=0 1k = 1 als i = j <strong>en</strong><br />

� 1 n−1<br />

n k=0 (ωi × (ω −1<br />

j )) k = 1 �n−1 n k=0 ωk m = 0 als i �= j<br />

De algoritme voor de inverse Fourier transformatie kan dus dezelfde zijn <strong>en</strong> dus is die ook <strong>van</strong> dezelfde<br />

complexiteit. In totaal is er dus voor de verm<strong>en</strong>igvuldiging O(n log n + n + n log n) = O(n log n) nodig.<br />

4.4 Snelle Machtsverheffing<br />

In 4.5 hieronder zull<strong>en</strong> we niet alle<strong>en</strong> grote getall<strong>en</strong> met elkaar moet<strong>en</strong> verm<strong>en</strong>igvuldig<strong>en</strong>, maar we zull<strong>en</strong> zelfs<br />

macht<strong>en</strong> <strong>van</strong> grote getall<strong>en</strong> moet<strong>en</strong> berek<strong>en</strong><strong>en</strong>. Gegev<strong>en</strong> e<strong>en</strong> snelle verm<strong>en</strong>igvuldigingsalgoritme is er ook e<strong>en</strong><br />

snelle algoritme om macht<strong>en</strong> te berek<strong>en</strong><strong>en</strong>. Deze algoritme is <strong>van</strong> het type ” verdeel <strong>en</strong> heers” <strong>en</strong> is één <strong>van</strong><br />

de oudst bek<strong>en</strong>de algoritm<strong>en</strong> <strong>van</strong> deze soort. Eerst merk<strong>en</strong> we op dat de naïeve berek<strong>en</strong>ing <strong>van</strong> a n ongeveer<br />

n verm<strong>en</strong>igvuldiging<strong>en</strong> <strong>van</strong> a met zichzelf vereist, <strong>en</strong> dat bov<strong>en</strong>di<strong>en</strong> de operand<strong>en</strong> in die verm<strong>en</strong>igvuldiging<br />

in ongeveer elke stap twee keer zo lang word<strong>en</strong>, zodat zeker na e<strong>en</strong> klein aantal stapp<strong>en</strong> de l<strong>en</strong>gte <strong>van</strong> de<br />

getall<strong>en</strong> mee moet word<strong>en</strong> g<strong>en</strong>om<strong>en</strong> in de complexiteit <strong>van</strong> de algoritme. Nu geldt dat a n = (a n/2 ) 2 als a<br />

ev<strong>en</strong> is, <strong>en</strong> a n = a n−1 ×a als a onev<strong>en</strong> is. Dit betek<strong>en</strong>t dat e<strong>en</strong> verdeel-<strong>en</strong>-heersalgoritme voor a n de volg<strong>en</strong>de<br />

complexiteit heeft.<br />

Dit is e<strong>en</strong> eig<strong>en</strong>aardige functie. Bijvoorbeeld<br />

⎧<br />

⎨ 0 als n = 1<br />

T (n) = T (n/2) + 1<br />

⎩<br />

T (n − 1) + 1<br />

als n ev<strong>en</strong> is<br />

als n onev<strong>en</strong> is<br />

T (31) = T (30) + 1 = T (15) + 2 = T (14) + 3 = T (7) + 4 =<br />

= T (6) + 5 = T (3) + 6 = T (2) + 7 = T (1) + 8 = 8<br />

T (32) = T (16) + 1 = T (8) + 2 = T (4) + 3 = T (2) + 4 = T (1) + 5 = 5<br />

Voor T (2 n ) zi<strong>en</strong> we n halveringsstapp<strong>en</strong>, zodat T (2 n ) = n, terwijl voor T (2 n − 1) we n − 1 halveringsstapp<strong>en</strong><br />

<strong>en</strong> n − 1 stapp<strong>en</strong> T (i) → T (i − 1), zodat T (2 n − 1) = 2(n − 1). Met inductie:<br />

T (2 n+1 ) = T (2 n ) + 1 = n + 1<br />

T (2 n+1 − 1) = T (2 n+1 − 2) + 1 = T (2(2 n − 1)) + 1 = T (2 n − 1) + 2 =<br />

= 2(n − 1) + 2 = 2n<br />

Omdat deze functie niet uiteindelijk niet dal<strong>en</strong>d is, kunn<strong>en</strong> we niet toepass<strong>en</strong> wat we in Som 6(in 1.3.2)<br />

op pagina 26 hebb<strong>en</strong> bewez<strong>en</strong>. We merk<strong>en</strong> echter op dat de functie lineair is, dus misschi<strong>en</strong> kunn<strong>en</strong> we<br />

77<br />

.


ov<strong>en</strong> <strong>en</strong> ondergr<strong>en</strong>z<strong>en</strong> vind<strong>en</strong> die wel monotoon zijn. Als n > 1 onev<strong>en</strong> is, dan is T (n) = T (n − 1) + 1 =<br />

T ((n − 1)/2) + 2 = T (⌊n/2⌋) + 2. Als n ev<strong>en</strong> is, dan is T (n) = T (⌊n/2⌋) + 1, dus altijd geldt:<br />

T (⌋n/2⌋) + 1 ≤ T (n) ≤ T (⌊n/2⌋) + 2.<br />

T wordt dus <strong>van</strong> b<strong>en</strong>ed<strong>en</strong>, resp. <strong>van</strong> bov<strong>en</strong> begr<strong>en</strong>sd door de functies T1 <strong>en</strong> T2 met<br />

�<br />

0 als n = 1<br />

Ti(n) =<br />

Ti(⌊n/2⌋) + i anders<br />

Omdat T1 ≤ T ≤ T2 <strong>en</strong> beide functies in θ(log n) zitt<strong>en</strong> geldt ook T (n) ∈ θ(log n). Ofwel we kunn<strong>en</strong><br />

machtsverheffing do<strong>en</strong> met e<strong>en</strong> aantal verm<strong>en</strong>igvuldiging<strong>en</strong> dat lineair is de l<strong>en</strong>gte <strong>van</strong> de expon<strong>en</strong>t. De<br />

efficiënte methode voor verm<strong>en</strong>igvuldig<strong>en</strong> hierbov<strong>en</strong> beschrev<strong>en</strong> geeft dat machtsverheffing in tijd O(n 2 log n)<br />

waarin n e<strong>en</strong> bov<strong>en</strong>gr<strong>en</strong>s is voor de l<strong>en</strong>gte <strong>van</strong> de expon<strong>en</strong>t <strong>en</strong> de grootste te verm<strong>en</strong>igvuldig<strong>en</strong> getall<strong>en</strong>.<br />

4.4.1 somm<strong>en</strong><br />

1. Het produkt <strong>van</strong> twee polynom<strong>en</strong> f <strong>en</strong> g waarbij de de coëffici<strong>en</strong>t<strong>en</strong> <strong>van</strong> x k − i in f <strong>en</strong> x i in g met<br />

elkaar verm<strong>en</strong>igvuldigd word<strong>en</strong> <strong>en</strong> vervolg<strong>en</strong>s voor alle i ≤ k bij elkaar opgeteld word<strong>en</strong> om in het<br />

produktpolynoom de coëffici<strong>en</strong>t <strong>van</strong> x k te vorm<strong>en</strong>, wordt ook wel ” convolutieproduct” g<strong>en</strong>oemd. (Dit<br />

begrip heeft in de algebra e<strong>en</strong> nog veel ruimere betek<strong>en</strong>is.) Met de DFT kunn<strong>en</strong> we nu zo’n produkt<br />

snel uitrek<strong>en</strong><strong>en</strong>. Gebruik de DFT voor de polynom<strong>en</strong> met coëffici<strong>en</strong>t<strong>en</strong> 1,2,3,4 <strong>en</strong> 4,3,2,1.<br />

2. Voor elke verzameling {x0, . . . , xn−1} <strong>van</strong> reële getall<strong>en</strong> is er precies één n-de graads monadisch (dwz. de<br />

coëffici<strong>en</strong>t <strong>van</strong> de hoogstegraadsterm is 1) polynoom, dat voor precies die waard<strong>en</strong> 0 wordt, namelijk<br />

(x − x0)(x − x1) . . . (x − xn−1). Geef e<strong>en</strong> Verdeel-<strong>en</strong>-heersalgoritme die dit polynoom in coëffici<strong>en</strong>t<strong>en</strong><br />

geeft in tijd O(n log 2 n).<br />

4.5 Cryptografie<br />

Bij het uitwissel<strong>en</strong> <strong>en</strong> bewar<strong>en</strong> <strong>van</strong> gevoelige gegev<strong>en</strong>s is het <strong>van</strong> belang dat deze niet tuss<strong>en</strong>tijds door derd<strong>en</strong><br />

kunn<strong>en</strong> word<strong>en</strong> gelez<strong>en</strong> <strong>en</strong>/of bewerkt. Behalve het letterlijk achter slot <strong>en</strong> gr<strong>en</strong>del houd<strong>en</strong> <strong>van</strong> de gegev<strong>en</strong>s<br />

(dat houdt in zorg<strong>en</strong> dat niemand erbij kan door de deur waarachter zich de gegev<strong>en</strong>s bevind<strong>en</strong> geslot<strong>en</strong> te<br />

houd<strong>en</strong>), is ook de versleuteling <strong>van</strong> de gegev<strong>en</strong>s <strong>van</strong> belang. E<strong>en</strong> goed cryptosysteem kan ervoor zorg<strong>en</strong><br />

dat, zelfs als e<strong>en</strong> derde persoon fysiek toegang krijgt tot de data, zij er niets mee kan do<strong>en</strong>. Cryptosystem<strong>en</strong><br />

hebb<strong>en</strong> de eig<strong>en</strong>schap dat geauthoriseerde person<strong>en</strong> gemakkelijk, dat wil zegg<strong>en</strong> computationeel e<strong>en</strong>voudig,<br />

toegang hebb<strong>en</strong> tot de data, terwijl niet geauthoriseerde person<strong>en</strong> moeilijk (bij voorkeur ge<strong>en</strong>) toegang<br />

hebb<strong>en</strong> tot de data. Aangezi<strong>en</strong> aang<strong>en</strong>om<strong>en</strong> moet word<strong>en</strong> dat beid<strong>en</strong> toegang hebb<strong>en</strong> tot de bron <strong>van</strong> de<br />

(bewerkte) data, moet<strong>en</strong> geauthoriseerde person<strong>en</strong> dus beschikk<strong>en</strong> over e<strong>en</strong> hoeveelheid extra informatie, die<br />

de brondata zinvol maakt.<br />

Deze extra informatie wordt sleutel g<strong>en</strong>oemd. Als meerdere person<strong>en</strong> toegang moet<strong>en</strong> hebb<strong>en</strong> tot de<br />

informatie, of als het bijvoorbeeld over informatie gaat die over e<strong>en</strong> onbetrouwbare lijn moet word<strong>en</strong> verstuurd<br />

wordt het ingewikkeld. Dan moet<strong>en</strong> meerdere person<strong>en</strong> zo’n sleutel del<strong>en</strong>, verschill<strong>en</strong>de sleutels moet<strong>en</strong><br />

toegang bied<strong>en</strong> tot dezelfde informatie, of de informatie moet op verschill<strong>en</strong>de manier<strong>en</strong> versleuteld kunn<strong>en</strong><br />

word<strong>en</strong>. In het laatste geval kan de <strong>en</strong>e partij versleutelde informatie verstur<strong>en</strong> zonder k<strong>en</strong>nis te hebb<strong>en</strong><br />

<strong>van</strong> de sleutel <strong>van</strong> de andere partij. In het eerste geval is de versleuteling symmetrisch (de sleutel die<br />

nodig is om te versleutel<strong>en</strong> is dezelfde als de sleutel nodig om de informatie terug te vind<strong>en</strong>). De laatste<br />

situatie is asymmetrisch, de sleutel nodig om de informatie te versleutel<strong>en</strong> is e<strong>en</strong> andere dan die nodig is om de<br />

informatie terug te winn<strong>en</strong>. In het eerste geval is het noodzakelijk de sleutel geheim te houd<strong>en</strong> bij de partij<strong>en</strong><br />

die informatie uitwissel<strong>en</strong> (dit systeem wordt daarom “private key” g<strong>en</strong>oemd) in het tweede geval is het niet<br />

altijd nodig de sleutel die gebruikt wordt om te versleutel<strong>en</strong> geheim te houd<strong>en</strong>. Deze zou door meerdere<br />

partij<strong>en</strong> kunn<strong>en</strong> word<strong>en</strong> gebruikt om e<strong>en</strong> versleutelde boodschap te stur<strong>en</strong>, mits deze versleuteling wel de<br />

eig<strong>en</strong>schap heeft dat zij alle<strong>en</strong> met de juiste decodeersleutel kan word<strong>en</strong> teruggedraaid (het is gebruikelijk<br />

de codeersleutel publiek te mak<strong>en</strong> <strong>en</strong> daarom word<strong>en</strong> zulke system<strong>en</strong> wel “public key” g<strong>en</strong>oemd).<br />

78


4.5.1 Private Key<br />

One Time Pad<br />

De <strong>en</strong>ige werkelijk veilige methode voor versleuteling waarbij beide partij<strong>en</strong> e<strong>en</strong> sleutel del<strong>en</strong> is ook e<strong>en</strong><br />

bijzonder simpele, de zog<strong>en</strong>oemde one-time pad. Hierbij kiez<strong>en</strong> beide partij<strong>en</strong> e<strong>en</strong> string random geg<strong>en</strong>ereerde<br />

bits als sleutel die net zo lang is als de te coder<strong>en</strong> boodschap. Vervolg<strong>en</strong>s wordt de versleutelde boodschap<br />

berek<strong>en</strong>d door bitsgewijs de XOR te nem<strong>en</strong> met de sleutel. De ont<strong>van</strong>g<strong>en</strong>de partij neemt bitsgewijs de XOR<br />

met dezelfde sleutel <strong>en</strong> krijgt de oorspronkelijke boodschap terug. Omdat de XOR <strong>van</strong> e<strong>en</strong> random bitstring<br />

met IEDERE bitstring weer e<strong>en</strong> random bitstring oplevert, kan e<strong>en</strong> afgeluisterde boodschap nooit word<strong>en</strong><br />

gedecodeerd. Nadeel <strong>van</strong> deze methode is wel dat e<strong>en</strong> zeer lange sleutel eerst via e<strong>en</strong> veilig kanaal moet<br />

word<strong>en</strong> uitgewisseld. In de praktijk is deze methode daarom onbruikbaar.<br />

kortere sleutels<br />

Hoe lang de sleutel moet zijn om (<strong>en</strong>ige) bescherming te bied<strong>en</strong> hangt af <strong>van</strong> de gebruikte versleutelingsalgoritme<br />

<strong>en</strong> <strong>van</strong> de computationele kracht <strong>van</strong> de teg<strong>en</strong>stander. Sleutels word<strong>en</strong> daarom langer naarmate<br />

die computationele kracht (<strong>en</strong> de eig<strong>en</strong> computationele kracht) groeit, <strong>en</strong> versleutelingsalgoritm<strong>en</strong> word<strong>en</strong><br />

ingewikkelder. Aangezi<strong>en</strong> het uitwissel<strong>en</strong> <strong>van</strong> geheime sleutels e<strong>en</strong> zeldzame <strong>en</strong> dure operatie is, wordt dezelfde<br />

sleutel vaak hergebruikt, veelal zelfs in één <strong>en</strong> dezelfde boodschap. Deze boodschap wordt daarom<br />

onderverdeeld in blokk<strong>en</strong> <strong>van</strong> hetzelfde aantal bits, waarop de versleuteling wordt toegepast. Vanwege deze<br />

onderverdeling word<strong>en</strong> dergelijk algoritm<strong>en</strong> ” block cypers” g<strong>en</strong>oemd. Er zijn veel block cyphers bek<strong>en</strong>d 1 , <strong>en</strong><br />

veel <strong>van</strong> deze zijn gebaseerd op e<strong>en</strong> zog<strong>en</strong>oemd Feistel netwerk beschrev<strong>en</strong> door Horst Feistel <strong>van</strong> IBM in<br />

1973. E<strong>en</strong> Feistel netwerk is e<strong>en</strong> algoritme die e<strong>en</strong> blok data <strong>van</strong> e<strong>en</strong> bepaald aantal bits versleutelt in e<strong>en</strong><br />

aantal rondes, waarbij de volg<strong>en</strong>de bewerking in iedere ronde wordt toegepast.<br />

1. verdeel het blok in twee helft<strong>en</strong>;<br />

2. pas e<strong>en</strong> rondefunctie F toe op de rechterhelft;<br />

3. neem de XOR <strong>van</strong> de versleutelde rechterhelft <strong>en</strong> de linkerhelft; Dat is de nieuwe linkerhelft.<br />

4. wissel de linker <strong>en</strong> rechterhelft om.<br />

Ontsleuteling <strong>van</strong> de boodschap gebeurt door het toepass<strong>en</strong> <strong>van</strong> de versleutelingsalgoritme in omgekeerde<br />

volgorde, met gebruikmaking <strong>van</strong> F −1 als rondefunctie.<br />

4.5.2 Sleutel Del<strong>en</strong><br />

E<strong>en</strong> <strong>van</strong> de eerste b<strong>en</strong>odigdhed<strong>en</strong> bij het gebruik <strong>van</strong> e<strong>en</strong> private key cryptosysteem is het del<strong>en</strong> <strong>van</strong> e<strong>en</strong><br />

sleutel. Partij<strong>en</strong> A <strong>en</strong> B kunn<strong>en</strong> zo’n sleutel natuurlijk <strong>van</strong>tevor<strong>en</strong> afsprek<strong>en</strong>, vervolg<strong>en</strong>s uit elkaar gaan <strong>en</strong><br />

de sleutel gaan gebruik<strong>en</strong>, maar ge<strong>en</strong> <strong>en</strong>kele sleutel kan veilig onafgebrok<strong>en</strong> word<strong>en</strong> gebruikt. Regelmatig<br />

moet e<strong>en</strong> sleutel word<strong>en</strong> vernieuwd om het systeem veilig te houd<strong>en</strong>. Nieuwe sleutels kunn<strong>en</strong> natuurlijk<br />

word<strong>en</strong> uitgewisseld door elkaar fysiek te ontmoet<strong>en</strong> <strong>en</strong> e<strong>en</strong> nieuwe sleutel af te sprek<strong>en</strong>. Dit is echter altijd<br />

duur <strong>en</strong> lang niet altijd uitvoerbaar. Ook kan natuurlijk zo lang de eerste sleutel nog veilig is, e<strong>en</strong> nieuwe<br />

sleutel word<strong>en</strong> aangemaakt <strong>en</strong> gecodeerd word<strong>en</strong> verzond<strong>en</strong>. Dit heeft echter het nadeel dat e<strong>en</strong> deel <strong>van</strong><br />

de veiligheid die de sleutel heeft wordt aangew<strong>en</strong>d om e<strong>en</strong> nieuwe sleutel te verstur<strong>en</strong> (<strong>en</strong> dus niet voor het<br />

coder<strong>en</strong> <strong>van</strong> boodschapp<strong>en</strong>) <strong>en</strong> houdt bov<strong>en</strong>di<strong>en</strong> het risico in dat, omdat je niet zeker kunt wet<strong>en</strong> wanneer<br />

e<strong>en</strong> sleutel niet meer kan word<strong>en</strong> gebruikt, de sleutel door derd<strong>en</strong> is gevond<strong>en</strong> voordat e<strong>en</strong> nieuwe sleutel<br />

wordt verstuurd (waardoor de nieuwe sleutel al mete<strong>en</strong> is gevond<strong>en</strong>).<br />

1 onder andere: 3-Way,AES, Akelarre, Anubis, Blowfish, C2, Camellia, CAST-128, CAST-256, CMEA, CS-Cipher, DEAL,<br />

DES, DES-X, FEAL, FROG, G-DES, GOST, Hasty Pudding Cipher, ICE, IDEA, IDEA NXT, Iraqi, KASUMI, KHAZAD,<br />

Khufu and Khafre, Libelle, LOKI89/91, LOKI97, Lucifer, MacGuffin, Madryga, MAGENTA, MARS, MISTY1, MMB, NewDES,<br />

Noekeon, RC2, RC5, RC6, REDOC, Red Pike, S-1, SAFER, SEED, Serp<strong>en</strong>t, SHACAL, SHARK, Skipjack, SMS4, Square, TEA,<br />

Triple DES, Twofish, XTEA<br />

79


Diffie <strong>en</strong> Helman [DH76], naar e<strong>en</strong> idee <strong>van</strong> Paul Merkle gebruikt<strong>en</strong> in 1976 de volg<strong>en</strong>de methode om e<strong>en</strong><br />

geheime sleutel te del<strong>en</strong> over e<strong>en</strong> onvelig kanaal. Neem e<strong>en</strong> groot priemgetal p. E<strong>en</strong> getal a kleiner dan p<br />

heet e<strong>en</strong> voortbr<strong>en</strong>ger of primitief elem<strong>en</strong>t <strong>van</strong> 1, . . . , p als {1, . . . , p} = {a, a 2 , a 3 , . . . , a p−1 } De macht<strong>en</strong> <strong>van</strong><br />

a lop<strong>en</strong> dan (mod p) langs alle getall<strong>en</strong> modulo p. Voor elk priemgetal p bestaat er minst<strong>en</strong>s één zo’n a. Stel<br />

dat er e<strong>en</strong> p, priemgetal, <strong>en</strong> e<strong>en</strong> a voortbr<strong>en</strong>ger <strong>van</strong> 1, . . . , p gegev<strong>en</strong> zijn. Twee partij<strong>en</strong> A <strong>en</strong> B kunn<strong>en</strong> nu<br />

als volgt e<strong>en</strong> sleutel uitwissel<strong>en</strong> over e<strong>en</strong> publiek kanaal. A kiest e<strong>en</strong> willekeurig getal XA < p <strong>en</strong> berek<strong>en</strong>t<br />

YA = a XA mod p. B kiest e<strong>en</strong> willekeurig getal XB < p <strong>en</strong> berek<strong>en</strong>t YB = a XB mod p. De waard<strong>en</strong> YA <strong>en</strong><br />

YB word<strong>en</strong> vervolg<strong>en</strong>s uitgewisseld, <strong>en</strong> XA <strong>en</strong> XB word<strong>en</strong> geheim gehoud<strong>en</strong>. A berek<strong>en</strong>t (YB) XA mod p <strong>en</strong><br />

B berek<strong>en</strong>t (YA) XB mod p. Zo krijg<strong>en</strong> ze allebei dezelfde waarde K in hand<strong>en</strong>. Immers<br />

K = (YB) XA mod p<br />

= (a XB mod p) XA mod p<br />

= (a XB ) XA mod p<br />

= (a XA ) XB mod p<br />

= (a XA mod p) XB mod p<br />

= (YA) XB mod p<br />

Omdat andere partij<strong>en</strong> niet de beschikking hebb<strong>en</strong> over de X waard<strong>en</strong> is de publiek gemaakte informatie,<br />

aang<strong>en</strong>om<strong>en</strong> dat het vind<strong>en</strong> <strong>van</strong> de discrete logaritme modulo p computationeel ondo<strong>en</strong>lijk is, waardeloos.<br />

4.5.3 Public Key<br />

Hoewel het verm<strong>en</strong>igvuldig<strong>en</strong> <strong>van</strong> getall<strong>en</strong> e<strong>en</strong> doel op zich is voor rek<strong>en</strong>automat<strong>en</strong> is het verm<strong>en</strong>igvuldig<strong>en</strong><br />

<strong>van</strong> echt grote getall<strong>en</strong> zeer veel meer in de belangstelling kom<strong>en</strong> te staan na de introductie <strong>van</strong> public key<br />

cryptosystem<strong>en</strong> als Rivest-Shamir-Adleman (RSA) uit 1978 [RSA78]. Het principe achter RSA is gebaseerd<br />

op de aanname dat de inverse operatie <strong>van</strong> verm<strong>en</strong>igvuldiging, het ontbind<strong>en</strong> <strong>van</strong> e<strong>en</strong> getal in zijn factor<strong>en</strong><br />

e<strong>en</strong> moeilijke operatie is, vooral wanneer het getal groot is (teg<strong>en</strong>woordig zo’n vierhonderd cijfers) <strong>en</strong> zelf het<br />

product is <strong>van</strong> twee priemgetall<strong>en</strong>. De best bek<strong>en</strong>de algoritme voor het ontbind<strong>en</strong> <strong>van</strong> e<strong>en</strong> getal in factor<strong>en</strong><br />

is teg<strong>en</strong>woordig de zog<strong>en</strong>oemde number field sieve (zie bijvoorbeeld [Pom96]). De snelste method<strong>en</strong> tot nu<br />

toe zijn echter nog steeds expon<strong>en</strong>tieel <strong>en</strong> daarom kunn<strong>en</strong> we bij voldo<strong>en</strong>de grote getall<strong>en</strong> er <strong>van</strong>uit gaan dat<br />

het lang duurt om e<strong>en</strong> factorisatie te vind<strong>en</strong>. E<strong>en</strong> cryptosysteem dat op deze aanname gebaseerd is werkt<br />

als volgt.<br />

De Euler toti<strong>en</strong>t functie, φ(n), is het aantal getall<strong>en</strong> kleiner dan of gelijk aan n dat relatief priem met n<br />

is.<br />

φ(n) = ♯{i | i < n ∧ ggd(i, n) = 1}<br />

Als n zelf e<strong>en</strong> priemgetal is, dan is dus φ(n) gelijk aan n − 1. Als n = p × q, e<strong>en</strong> getal e relatief priem is met<br />

φ(n) = (p − 1)(q − 1) <strong>en</strong> d de inverse is <strong>van</strong> e in Z φ(n), dan kan het drietal d, e, n gebruikt word<strong>en</strong> in e<strong>en</strong><br />

public key cryptosysteem, waarbij n <strong>en</strong> e gepubliceerd word<strong>en</strong> <strong>en</strong> d de geheime decodeersleutel is. Immers<br />

e<strong>en</strong> plaintext M in Zn kan gecodeerd word<strong>en</strong> als C = M e mod n. De gecodeerde boodschap C kan dan<br />

gedecodeerd word<strong>en</strong> als M = C d mod n = (M de mod n) = M 1 mod n = M, waarbij de tweede gelijkheid<br />

uit de stelling <strong>van</strong> Euler volgt 2 Om ervoor te zorg<strong>en</strong> dat d niet gemakkelijk uit e kan word<strong>en</strong> berek<strong>en</strong>d is het<br />

echter noodzakelijk dat p <strong>en</strong> q uit veel cijfers bestaan <strong>en</strong> dus dat de verm<strong>en</strong>igvuldiging efficiënt gedaan moet<br />

word<strong>en</strong>. Bov<strong>en</strong>di<strong>en</strong> moet er voor iedere gebruiker <strong>van</strong> het systeem e<strong>en</strong> nieuw paar p, q word<strong>en</strong> aangemaakt<br />

<strong>en</strong> is de algem<strong>en</strong>e regel dat e<strong>en</strong> sleutel voor e<strong>en</strong> coderingssysteem regelmatig moet word<strong>en</strong> ververst natuurlijk<br />

ook <strong>van</strong> toepassing.<br />

Het recept voor het krijg<strong>en</strong> <strong>van</strong> e<strong>en</strong> bruikbaar cryptosysteem is dus.<br />

1. G<strong>en</strong>ereeer twee grote priemgetall<strong>en</strong> p <strong>en</strong> q. Meestal word<strong>en</strong> deze random gekoz<strong>en</strong> omdat de kans e<strong>en</strong><br />

priemgetal te treff<strong>en</strong> onder de getall<strong>en</strong> kleiner dan n vrij groot is. Er zijn ongeveer n/ log n priemgetall<strong>en</strong><br />

kleiner dan n, dus de kans voor e<strong>en</strong> willekeurig getal is al 1/ log n, maar voor speciale getall<strong>en</strong> als 3<br />

mod 4 is de kans dat je e<strong>en</strong> priemgetal treft nog aanzi<strong>en</strong>lijk groter.<br />

2 De stelling <strong>van</strong> Euler zegt dat voor positieve a <strong>en</strong> n die relatief priem zijn geldt dat a φ(n) = 1. Dus geldt M de = M 1+kφ(n) =<br />

M, t<strong>en</strong>zij M = p of M = q.<br />

80


2. Kies e<strong>en</strong> getal e dat relatief priem is met (p − 1)(q − 1). Ook hier kun je volstaan met e<strong>en</strong> random getal<br />

waarbij je met de uitgebreide algoritme <strong>van</strong> Euclides raz<strong>en</strong>dsnel kunt test<strong>en</strong> dat je inderdaad e<strong>en</strong> getal<br />

hebt gevond<strong>en</strong> dat relatief priem met (p − 1)(q − 1) is <strong>en</strong> ook nog e<strong>en</strong> d kunt vind<strong>en</strong> die de inverse <strong>van</strong><br />

e is.<br />

3. Publiceer n <strong>en</strong> e <strong>en</strong> gebruik d voor het decoder<strong>en</strong>.<br />

4.5.4 Priemgetall<strong>en</strong><br />

Sinds kort is bewez<strong>en</strong> dat het voor het test<strong>en</strong> <strong>van</strong> het al dan niet priem zijn <strong>van</strong> e<strong>en</strong> getal e<strong>en</strong> efficiënte<br />

algoritme bestaat.[AKS04] Deze algoritme is echter nog niet voldo<strong>en</strong>de uitgekristalliseerd om te hebb<strong>en</strong><br />

geleid tot industriële toepassing<strong>en</strong>. In de praktijk is het ook voldo<strong>en</strong>de met redelijke zekerheid te wet<strong>en</strong><br />

dat de getall<strong>en</strong> die gebruikt word<strong>en</strong> voor het RSA systeem priemgetall<strong>en</strong> zijn. We zull<strong>en</strong> daarom alle<strong>en</strong><br />

kort de meest in gebruik zijnde methode voor het verifiër<strong>en</strong> <strong>van</strong> de primaliteit <strong>van</strong> e<strong>en</strong> getal in deze tekst<br />

besprek<strong>en</strong>. Deze verificatie gaat met behulp <strong>van</strong> e<strong>en</strong> algoritme die gebruik maakt <strong>van</strong> e<strong>en</strong> random g<strong>en</strong>erator.<br />

De algoritme heeft, als hij gebruikt wordt op e<strong>en</strong> invoer die niet e<strong>en</strong> priemgetal is, e<strong>en</strong> redelijke kans te<br />

ontdekk<strong>en</strong> dat de invoer niet priem is (ongeveer 1/2). Enige mal<strong>en</strong> herhal<strong>en</strong> <strong>van</strong> de algoritme met nieuwe<br />

willekeurig getrokk<strong>en</strong> getall<strong>en</strong> maakt dus de kans dat de invoer e<strong>en</strong> priemgetal is groter (nauwkeuriger, <strong>en</strong>ige<br />

mal<strong>en</strong> herhal<strong>en</strong> <strong>van</strong> de algoritme maakt de kans dat de algoritme niet de uitvoer ge<strong>en</strong> priemgetal zou gev<strong>en</strong><br />

onder de aanname dat de invoer ge<strong>en</strong> priemgetal is kleiner; natuurlijk is de invoer wel of juist niet e<strong>en</strong><br />

priemgetal <strong>en</strong> is er ge<strong>en</strong> sprake <strong>van</strong> kans<strong>en</strong>).<br />

De test is gebaseerd op de stelling <strong>van</strong> Fermat die (toegepast op priemgetall<strong>en</strong>) zegt.<br />

Stelling 4.5.1 Als n e<strong>en</strong> priemgetal is, dan geldt voor elke b < n dat b n−1 = 1 mod n.<br />

De kracht <strong>van</strong> deze test is dat je kunt bewijz<strong>en</strong> dat als n ge<strong>en</strong> priemgetal is, dan geldt b n−1 = 1 mod n<br />

voor hoogst<strong>en</strong>s de helft <strong>van</strong> de getall<strong>en</strong> kleiner dan n. Dit bewijs gev<strong>en</strong> we hier niet, maar kan op veel<br />

plaats<strong>en</strong> gevond<strong>en</strong> word<strong>en</strong> in standaard tekstboek<strong>en</strong>.<br />

4.5.5 somm<strong>en</strong><br />

1. Op veel plaats<strong>en</strong> (bijvoorbeeld www.prime-numbers.org) kunn<strong>en</strong> integers <strong>van</strong> beperkte grootte gevond<strong>en</strong><br />

word<strong>en</strong> die priem zijn, <strong>en</strong> tev<strong>en</strong>s kunn<strong>en</strong> zelf ingevoerde getall<strong>en</strong> op priemaliteit word<strong>en</strong> getest.<br />

Schrijf e<strong>en</strong> programma dat e<strong>en</strong> random getal trekt dat met grote kans priem is, <strong>en</strong> test het vervolg<strong>en</strong>s<br />

op zo’n site. (Getall<strong>en</strong> <strong>van</strong> de vorm 3 mod 4 zijn vaak priem.) Test het vervolg<strong>en</strong>s met behulp <strong>van</strong><br />

Fermat’s stelling e<strong>en</strong> paar keer).<br />

2. G<strong>en</strong>ereer nog e<strong>en</strong> priemgetal als in de vorige opgave <strong>en</strong> gebruik deze priemgetall<strong>en</strong> om e<strong>en</strong> RSA systeem<br />

op te zett<strong>en</strong>.<br />

4.6 Beveiliging <strong>van</strong> gegev<strong>en</strong>s<br />

Cryptografische method<strong>en</strong> kunn<strong>en</strong> gebruikt word<strong>en</strong> voor verschill<strong>en</strong>de vorm<strong>en</strong> <strong>van</strong> gegev<strong>en</strong>sbeveiliging. Computers<br />

zijn teg<strong>en</strong>woordig vaak via netwerk<strong>en</strong> met elkaar verbond<strong>en</strong> <strong>en</strong> wissel<strong>en</strong> over die netwerk<strong>en</strong> gegev<strong>en</strong>s<br />

met elkaar uit. Niet elk pakketje data dat door computers wordt uitgewisseld moet door iedere<strong>en</strong> die toevallig<br />

ook op die lijn aanwezig is kunn<strong>en</strong> word<strong>en</strong> gelez<strong>en</strong>, <strong>en</strong> als we e<strong>en</strong> pakketje data ont<strong>van</strong>g<strong>en</strong> <strong>van</strong> e<strong>en</strong><br />

computer, dan will<strong>en</strong> we graag wet<strong>en</strong> <strong>van</strong> welke computer dat pakketje afkomstig is. We kunn<strong>en</strong> de computer<br />

aan de andere kant <strong>van</strong> de lijn niet zi<strong>en</strong> dus zoud<strong>en</strong> we graag <strong>en</strong>ige vorm <strong>van</strong> id<strong>en</strong>tificatie verlang<strong>en</strong><br />

voordat we bijvoorbeeld e<strong>en</strong> opdracht <strong>van</strong> die computer aanvaard<strong>en</strong>. E<strong>en</strong> derde vorm is nog commitm<strong>en</strong>t.<br />

Stel bijvoorbeeld dat de computer <strong>van</strong> e<strong>en</strong> beleggingsmaatschappij e<strong>en</strong> aandel<strong>en</strong>handelaar opdracht geeft<br />

groot in te kop<strong>en</strong> in e<strong>en</strong> bepaald bedrijf. Vervolg<strong>en</strong>s gaat het slecht met dat bedrijf <strong>en</strong> de aandel<strong>en</strong> kelder<strong>en</strong>.<br />

De beleggingsmaatschappij zou nu kunn<strong>en</strong> bewer<strong>en</strong> dat de opdracht nooit verstuurd is <strong>en</strong> dat de handelaar<br />

deze opdracht zelf verzonn<strong>en</strong> heeft.<br />

81


Cryptografische method<strong>en</strong>, in het bijzonder de public key cryptosystems, bied<strong>en</strong> voor al deze problem<strong>en</strong><br />

e<strong>en</strong> oplossing <strong>en</strong> we zull<strong>en</strong> hier schets<strong>en</strong> hoe deze oplossing<strong>en</strong> werk<strong>en</strong>. Het beveilig<strong>en</strong> <strong>van</strong> data teg<strong>en</strong> ongewild<br />

lez<strong>en</strong> door derd<strong>en</strong> is de standaardtoepassing, dus zull<strong>en</strong> we dat onderwerp niet nogmaals behandel<strong>en</strong>.<br />

4.6.1 Id<strong>en</strong>tificatie<br />

Als we e<strong>en</strong> opdracht <strong>van</strong> persoon P krijg<strong>en</strong> om uit te voer<strong>en</strong>, zoud<strong>en</strong> we graag will<strong>en</strong> vaststell<strong>en</strong> dat de<br />

persoon P inderdaad is wie ze zegt te zijn. De opdracht zelf zal gecodeerd zijn met onze eig<strong>en</strong> publiek<br />

gemaakte sleutel cm, dus deze zull<strong>en</strong> we kunn<strong>en</strong> decoder<strong>en</strong> met onze eig<strong>en</strong>, geheim gehoud<strong>en</strong>, sleutel dm.<br />

Hoe wet<strong>en</strong> we dat de boodschap afkomstig is <strong>van</strong> P ?<br />

P heeft, net als alle andere deelnemers, in het publieke domein e<strong>en</strong> sleutel cp gedeponeerd, of deze sleutel<br />

is daar gezet door e<strong>en</strong> vertrouwde derde partij. Verder heeft P haar eig<strong>en</strong> geheime decodeersleutel dp. De<br />

id<strong>en</strong>tificatie <strong>van</strong> de boodschap M wordt nu bereikt met het omgekeerde coderingsproces. P verstuurt de<br />

boodschap (P ) dp als onderdeel <strong>van</strong> M. P dp kan nu word<strong>en</strong> gelez<strong>en</strong> met behulp <strong>van</strong> de codeersleutel <strong>van</strong> P ,<br />

die publiek is ((P dp ) cp = P ). Niemand anders had deze boodschap kunn<strong>en</strong> verstur<strong>en</strong> zonder k<strong>en</strong>nis <strong>van</strong> dp<br />

4.6.2 Commitm<strong>en</strong>t<br />

E<strong>en</strong> soortgelijk schema kan word<strong>en</strong> gebruikt voor commitm<strong>en</strong>t. De boodschap M = ” Koop 5000 aandel<strong>en</strong>”<br />

kan word<strong>en</strong> gecodeerd met de publieke sleutel cp maar ook ondertek<strong>en</strong>d met de hierbov<strong>en</strong>beschrev<strong>en</strong> id<strong>en</strong>tificatieprocedure.<br />

Aangezi<strong>en</strong> de id<strong>en</strong>tificatie uniek is kan de gecodeerde boodschap ook di<strong>en</strong><strong>en</strong> als bewijs dat<br />

de boodschap verzond<strong>en</strong> is. De ont<strong>van</strong>ger kan immers niet zelf de id<strong>en</strong>tificatie geproduceerd hebb<strong>en</strong>.<br />

4.6.3 somm<strong>en</strong><br />

1. Gebruik het RSA systeem uit som 2 om e<strong>en</strong> docum<strong>en</strong>t <strong>van</strong> e<strong>en</strong> handtek<strong>en</strong>ing te voorzi<strong>en</strong>.<br />

82


Deel II<br />

<strong>Complexiteit</strong>stheorie<br />

83


In dit deel <strong>van</strong> de tekst abstraher<strong>en</strong> we <strong>van</strong> specifieke algoritm<strong>en</strong> voor problem<strong>en</strong> <strong>en</strong> kijk<strong>en</strong> naar de<br />

complexiteit <strong>van</strong> de problem<strong>en</strong> zelf. Om uitsprak<strong>en</strong> te do<strong>en</strong> over alle mogelijke algoritm<strong>en</strong> die voor e<strong>en</strong><br />

probleem kunn<strong>en</strong> bestaan, <strong>en</strong> de complexiteit daar<strong>van</strong> hebb<strong>en</strong> we e<strong>en</strong> e<strong>en</strong>voudig maar g<strong>en</strong>eriek toepasbaar<br />

model voor berek<strong>en</strong>ing nodig. Hier<strong>van</strong> zijn diverse voorbeeld<strong>en</strong> voorhand<strong>en</strong>, die allemaal modulo de juiste<br />

overhead uitwisselbaar zijn. Vervolg<strong>en</strong>s kunn<strong>en</strong> we problem<strong>en</strong> onderverdel<strong>en</strong> in complexiteitsklass<strong>en</strong>. De<br />

klasse NP <strong>en</strong> de volledige problem<strong>en</strong> in die klasse spel<strong>en</strong> in dit deel e<strong>en</strong> speciale rol.<br />

85


Hoofdstuk 5<br />

Modell<strong>en</strong> voor Berek<strong>en</strong>ing<br />

In het eerste deel <strong>van</strong> deze tekst hebb<strong>en</strong> we e<strong>en</strong> informeel model voor berek<strong>en</strong>ing gebruikt. We hebb<strong>en</strong> de<br />

complexiteit <strong>van</strong> algoritm<strong>en</strong> opgehang<strong>en</strong> aan zog<strong>en</strong>oemde spil-operaties (pagina 16) die niet nader g<strong>en</strong>oemde<br />

kost<strong>en</strong> hadd<strong>en</strong>, maar waar<strong>van</strong> we aannam<strong>en</strong> dat ze op e<strong>en</strong> andere computer ook kond<strong>en</strong> word<strong>en</strong> uitgevoerd<br />

voor kost<strong>en</strong> die niet meer dan e<strong>en</strong> constante keer zo groot zijn, waarbij de aanname dan ook nog was dat<br />

die constante beperkt zou zijn. In dit deel <strong>van</strong> de tekst zull<strong>en</strong> we wat preciezer word<strong>en</strong> over het model<br />

dat we voor de berek<strong>en</strong>ing gebruik<strong>en</strong>, omdat we het hier over problem<strong>en</strong> hebb<strong>en</strong> <strong>en</strong> bewijz<strong>en</strong> will<strong>en</strong> gaan<br />

gev<strong>en</strong> die voor alle algoritm<strong>en</strong> geld<strong>en</strong> die bij die problem<strong>en</strong> hor<strong>en</strong>. In het bijzonder will<strong>en</strong> we <strong>van</strong> problem<strong>en</strong><br />

graag bewijz<strong>en</strong> dat er ge<strong>en</strong> efficiënte algoritm<strong>en</strong> voor bestaan. Natuurlijk mag zo’n bewijs nooit afhang<strong>en</strong><br />

<strong>van</strong> de specifieke computer waarop zo’n algoritme wordt uitgevoerd. We zull<strong>en</strong> dus in het bijzonder e<strong>en</strong><br />

probleem als ondo<strong>en</strong>lijk classificer<strong>en</strong> als er ge<strong>en</strong> efficiënte algoritme bestaat voor dit probleem op e<strong>en</strong> redelijk<br />

machinemodel. Voor effiënte algoritm<strong>en</strong> hebb<strong>en</strong> we in het eerste deel al betoogd, dat deze klasse beperkt<br />

is tot de algoritm<strong>en</strong> waar<strong>van</strong> de tijdgr<strong>en</strong>z<strong>en</strong> beperkt zijn tot polynom<strong>en</strong>. In ieder geval houd<strong>en</strong> we vast dat<br />

e<strong>en</strong> algoritme waar<strong>van</strong> de rek<strong>en</strong>tijd niet begr<strong>en</strong>sd is door e<strong>en</strong> polynoom niet efficiënt is. In het kader <strong>van</strong><br />

de machinemodell<strong>en</strong> zull<strong>en</strong> we naar analogie e<strong>en</strong> klasse <strong>van</strong> machinemodell<strong>en</strong> aanwijz<strong>en</strong> die elkaar kunn<strong>en</strong><br />

simuler<strong>en</strong> in polynomiaal begr<strong>en</strong>sde tijd. Dat wil zegg<strong>en</strong> dat wat op de <strong>en</strong>e machine in n stapp<strong>en</strong> kan<br />

word<strong>en</strong> uitgevoerd, kan op de andere machine in p(n) stapp<strong>en</strong> word<strong>en</strong> uitgevoerd voor p e<strong>en</strong> polynoom <strong>van</strong><br />

bij voorkeur lage graad. Als e<strong>en</strong> machine bijvoorbeeld in log n stapp<strong>en</strong> kan do<strong>en</strong> wat onze machine in n<br />

stapp<strong>en</strong> doet, dan zull<strong>en</strong> we die machine niet zi<strong>en</strong> als e<strong>en</strong> redelijke machine. De uitspraak ” alle redelijke<br />

machinemodell<strong>en</strong> simuler<strong>en</strong> elkaar in polynomiale tijd begr<strong>en</strong>sde overhead <strong>en</strong> constante factor overhead in<br />

ruimte” staat bek<strong>en</strong>d als de sequ<strong>en</strong>tial computation thesis. Omdat dit nogal wat ruimte inneemt zull<strong>en</strong> we<br />

deze uitspraak voortaan aanduid<strong>en</strong> met ” redelijkheidsaanname”.<br />

5.1 Redelijke Machinemodell<strong>en</strong><br />

Er zijn talloze voorbeeld<strong>en</strong> <strong>van</strong> redelijke machinemodell<strong>en</strong>. Twee hier<strong>van</strong> zull<strong>en</strong> we in dit hoofdstuk besprek<strong>en</strong>.<br />

De Random Acces Machine <strong>en</strong> de Turing Machine.<br />

5.1.1 De Random Access Machine<br />

E<strong>en</strong> in veel boek<strong>en</strong> gebruikt model voor berek<strong>en</strong>ing is de Random Access Machine, omdat het model veel<br />

lijkt op in de praktijk nog steeds gebruikte machines. De Random Access Machine (Figuur 5.1) bestaat<br />

uit e<strong>en</strong> c<strong>en</strong>trale verwerkingse<strong>en</strong>heid, de processor, aangevuld met e<strong>en</strong> onbegr<strong>en</strong>sd geheug<strong>en</strong> dat bestaat uit<br />

e<strong>en</strong> onbegr<strong>en</strong>sd aantal registers. In elk register kan e<strong>en</strong> natuurlijk getal word<strong>en</strong> opgeslag<strong>en</strong>. De Random<br />

Access Machine heeft e<strong>en</strong> programma bestaande uit g<strong>en</strong>ummerde instructies. De machine begint altijd met<br />

het uitvoer<strong>en</strong> <strong>van</strong> instructie nummer 1 <strong>en</strong> stopt als zij de instructie HALT teg<strong>en</strong>komt. Verder heeft zij de<br />

volg<strong>en</strong>de set instructies.<br />

87


Figuur 5.1: Random Access Machine<br />

LOAD i : Haal wat er in register i zit op <strong>en</strong> sla dat op in de processor<br />

STORE i : Stop wat er in de processor staat in register i.<br />

ADD i : Tel wat er in de processor staat op bij wat er in het register i staat <strong>en</strong> sla dat op in de processor.<br />

SUB i : Trek wat er in register i staat af <strong>van</strong> wat er in de processor staat <strong>en</strong> sla dat op in de processor.<br />

JUMP a : Spring naar opdrachtregel a.<br />

JGTZ a : Als wat er in de processor staat groter is dan 0 spring naar opdrachtregel a, ga anders door met<br />

de volg<strong>en</strong>de opdrachtregel.<br />

Verder kunn<strong>en</strong> alle getall<strong>en</strong> in het programma word<strong>en</strong> voorafgegaan door e<strong>en</strong> # wat e<strong>en</strong> indirectie inhoudt.<br />

Dat betek<strong>en</strong>t dat niet dat getal moet word<strong>en</strong> gebruikt maar de inhoud <strong>van</strong> het register dat door dat getal<br />

wordt aangeduid. Bijvoorbeeld JGT Z#0 betek<strong>en</strong>t, als de inhoud <strong>van</strong> de processor groter dan 0 is, dan<br />

spring je naar de opdrachtregel die het nummer draagt <strong>van</strong> het getal dat in register 0 is opgeslag<strong>en</strong>. Om<br />

het model compleet te mak<strong>en</strong> zal de Random Access Machine niet alle<strong>en</strong> stopp<strong>en</strong> als de instructie HALT<br />

bereikt wordt, maar ook als er e<strong>en</strong> onzinnige opdracht verwerkt moet word<strong>en</strong>, bijvoorbeeld het spring<strong>en</strong> naar<br />

e<strong>en</strong> opdrachtregel die niet bestaat of het aflag<strong>en</strong> <strong>van</strong> e<strong>en</strong> register waar al 0 in staat. Dit is de zog<strong>en</strong>oemde<br />

CRASH opdracht.<br />

Tijd<br />

E<strong>en</strong> maat voor de tijd die door e<strong>en</strong> Random Access Machine wordt besteed aan het uitvoer<strong>en</strong> <strong>van</strong> e<strong>en</strong><br />

programma is de opdrachtregel. Elke uitvoering <strong>van</strong> e<strong>en</strong> opdrachtregel is één stap. In sommige gevall<strong>en</strong><br />

wordt ook de l<strong>en</strong>gte <strong>van</strong> de operand<strong>en</strong> <strong>van</strong> ADD <strong>en</strong> SUB instructies geteld, omdat in e<strong>en</strong> register nu e<strong>en</strong>maal<br />

e<strong>en</strong> willekeurig groot getal staat <strong>en</strong> in e<strong>en</strong> realistisch machinemodel niet willekeurig grote getall<strong>en</strong> in één<br />

stap bij elkaar kunn<strong>en</strong> word<strong>en</strong> opgeteld.<br />

Geheug<strong>en</strong><br />

E<strong>en</strong> maat voor het gebruikte geheug<strong>en</strong> <strong>van</strong> e<strong>en</strong> Random Access Machine is de hoeveelheid gebruikte registers.<br />

Aan het begin <strong>van</strong> de berek<strong>en</strong>ing is de inhoud <strong>van</strong> elke register 0 als er e<strong>en</strong> getal in zo’n register wordt<br />

geschrev<strong>en</strong>, dan telt <strong>van</strong>af dat mom<strong>en</strong>t het register mee in de hoeveelheid gebruikt geheug<strong>en</strong>. In sommmige<br />

gevall<strong>en</strong> wordt ook de som <strong>van</strong> de logaritm<strong>en</strong> <strong>van</strong> de inhoud<strong>en</strong> <strong>van</strong> de registers die niet nul zijn geteld als<br />

88


geheug<strong>en</strong>. Dit is om rek<strong>en</strong>ing te houd<strong>en</strong> met het feit dat in e<strong>en</strong> register e<strong>en</strong> willekeurig natuurlijk getal kan<br />

word<strong>en</strong> opgeslag<strong>en</strong>.<br />

5.1.2 De Turing Machine<br />

Eén <strong>van</strong> de eerste modell<strong>en</strong> voor berek<strong>en</strong>baarheid is de Turing machine, voor de eerste keer gepres<strong>en</strong>teerd<br />

in het artikel ” On computable numbers, with an application to the Entscheidungsproblem.” door Alan M.<br />

Turing in 1936 [Tur36]. Vóór de pres<strong>en</strong>tatie <strong>van</strong> het Turing machine model was de vraag wat precies e<strong>en</strong> algoritme<br />

of algoritmische bewerking is e<strong>en</strong> c<strong>en</strong>traal onderwerp <strong>van</strong> discussie. Het verschil tuss<strong>en</strong> algoritmisch<br />

<strong>en</strong> niet algoritmisch d<strong>en</strong>k<strong>en</strong> is onderwerp <strong>van</strong> filosofisch debat. Turing ging uit <strong>van</strong> de volg<strong>en</strong>de vooronderstelling.<br />

Zie de wiskundige als e<strong>en</strong> automaat die e<strong>en</strong> vel ruitjespapier tot zijn beschikking heeft. Het<br />

ruitjespapier is in vier richting<strong>en</strong> onbegr<strong>en</strong>sd, maar de wiskundige kan slechts e<strong>en</strong> beperkt aantal ruitjes (zeg<br />

één) tegelijkertijd lez<strong>en</strong>. Als zij e<strong>en</strong> ruitje gelez<strong>en</strong> heeft, kan zij dat onthoud<strong>en</strong>, e<strong>en</strong> nieuwe waarde in het<br />

zojuist gelez<strong>en</strong> ruitje schrijv<strong>en</strong> <strong>en</strong> naar e<strong>en</strong> andere plaats op het papier beweg<strong>en</strong>. Het aantal waard<strong>en</strong> dat zij<br />

kan onthoud<strong>en</strong> is begr<strong>en</strong>sd door één of andere constante.<br />

Teg<strong>en</strong>woordig wordt het ruitjespapier ver<strong>van</strong>g<strong>en</strong> door e<strong>en</strong> tweezijdig onbegr<strong>en</strong>sde band (zie Figuur 5.2).<br />

In elke cel <strong>van</strong> de band kan per bezoek één symbool geschrev<strong>en</strong> word<strong>en</strong> <strong>en</strong> het onthoud<strong>en</strong> <strong>van</strong> e<strong>en</strong> symbool<br />

wordt gekarakterizeerd doordat de machine (wiskundige) in e<strong>en</strong> begr<strong>en</strong>sd aantal toestand<strong>en</strong> kan zijn. Het<br />

programma dat de machine uitvoert is dan steeds: ” Als in toestand p symbool a gelez<strong>en</strong> wordt, dan komt<br />

de machine in toestand q, schrijft symbool b <strong>en</strong> beweegt naar links of naar rechts.” Het programma eindigt<br />

als er e<strong>en</strong> combinatie gelez<strong>en</strong> symbool/toestand actueel is waarvoor ge<strong>en</strong> opvolger in het programma staat,<br />

ofwel het gaat net zolang door tot het niet meer verder kan.<br />

Repres<strong>en</strong>taties<br />

Formeel bestaat het Turing machine model uit:<br />

Figuur 5.2: Het standaard Turing machinemodel<br />

1. E<strong>en</strong> eindige verzameling toestand<strong>en</strong> Q. E<strong>en</strong> speciale toestand q0 ∈ Q is aangemerkt als de begintoestand.<br />

2. E<strong>en</strong> eindige verzameling bandsymbol<strong>en</strong> Σ deze verzameling omvat altijd het blanco symbool B.<br />

3. E<strong>en</strong> toestandsovergangsfunctie δ : Q × Σ ↦→ Q × Σ × {L, R, ∅}<br />

Bij aan<strong>van</strong>g <strong>van</strong> de berek<strong>en</strong>ing bevat de band e<strong>en</strong> aane<strong>en</strong>geslot<strong>en</strong> eindige rij niet blanco symbol<strong>en</strong> <strong>en</strong> staat het<br />

eerste symbool <strong>van</strong> links op de posititie waar zich de tapekop bevindt. In sommige gevall<strong>en</strong> wordt de Turing<br />

machine nog uitgebreid door e<strong>en</strong> aantal <strong>van</strong> de toestand<strong>en</strong> ” eindtoestand<strong>en</strong>” te noem<strong>en</strong> <strong>en</strong> af te sprek<strong>en</strong> dat<br />

de Turingmachine stopt als zij in één <strong>van</strong> deze eindtoestand<strong>en</strong> komt. Dit is echter niet noodzakelijk.<br />

Voorbeeld 5.1.1: Er zijn verschill<strong>en</strong>de manier<strong>en</strong> om e<strong>en</strong> Turingmachine te repres<strong>en</strong>ter<strong>en</strong>, we zull<strong>en</strong> dit aan<br />

de hand <strong>van</strong> drietal voorbeeld<strong>en</strong> lat<strong>en</strong> zi<strong>en</strong> waarbij in elk voorbeeld het programma gebruikt wordt dat bij<br />

zijn invoer die uit 0 <strong>en</strong> 1 bestaat 1 optelt. Aangezi<strong>en</strong> de kop weg<strong>en</strong>s aanname op het eerste niet blanco<br />

89


symbool <strong>van</strong> links staat, moet zij eerst naar rechts tot het einde <strong>van</strong> de invoer lop<strong>en</strong> om aan die kant te<br />

prober<strong>en</strong> 1 bij de invoer op te tell<strong>en</strong>. De Turingmachine begint links op de band bij het eerste symbool. Dat<br />

is e<strong>en</strong> 1 of e<strong>en</strong> B. Als het e<strong>en</strong> B is, dan schrijft zij e<strong>en</strong> 1 <strong>en</strong> stopt. In het andere geval gaat de machine over<br />

in toestand q1 <strong>en</strong> beweegt naar rechts. In toestand q1 beweegt de Turingmachine net zo lang naar rechts<br />

totdat e<strong>en</strong> B wordt gelez<strong>en</strong>. Dan keert de machine om <strong>en</strong> komt in toestand q2. In toestand q2 wordt elke 1<br />

onder de kop veranderd in e<strong>en</strong> 0. De éérste 0 of B die teg<strong>en</strong>gekom<strong>en</strong> wordt, verandert in e<strong>en</strong> 1, waarna de<br />

machine stopt.<br />

1. Allereerst kunn<strong>en</strong> we natuurlijk de Turing machine repres<strong>en</strong>ter<strong>en</strong> door de toestandsovergangsfunctie<br />

expliciet te gev<strong>en</strong>. Dat ziet er als volgt uit.<br />

δ(q0, 1) = 〈q1, 1, R〉<br />

δ(q0, B) = 〈qF , 1, R〉<br />

δ(q1, 0) = 〈q1, 0, R〉<br />

δ(q1, 1) = 〈q1, 1, R〉<br />

δ(q1, B) = 〈q2, B, L〉<br />

δ(q2, 0) = 〈qF , 1, L〉<br />

δ(q2, 1) = 〈q2, 0, L〉<br />

δ(q2, B) = 〈qF , 1, L〉<br />

2. E<strong>en</strong> andere veelgebruikte manier is het schrijv<strong>en</strong> <strong>van</strong> de toestand<strong>en</strong> <strong>en</strong> de symbol<strong>en</strong> in e<strong>en</strong> tabel, waarbij<br />

de opdracht<strong>en</strong> de <strong>en</strong>tries <strong>van</strong> de tabel zijn.<br />

0 1 B<br />

q0 − q1, 1, R qF , 1, R<br />

q1 q1, 1, R q1, 0, L q2, B, L<br />

q2 qF , 1, L q2, 0, L qF , 1, L<br />

3. T<strong>en</strong>slotte is er nog de grafische manier <strong>van</strong> repres<strong>en</strong>ter<strong>en</strong>.<br />

q0<br />

��<br />

qF<br />

B/1/R<br />

1/1/R<br />

��<br />

X/1/R,X∈{0,B}<br />

��<br />

��<br />

q1<br />

��<br />

q2<br />

0/1/R<br />

X/X/R,X∈{0,1}<br />

Al deze method<strong>en</strong> zijn equival<strong>en</strong>t <strong>en</strong> kom<strong>en</strong> in de literatuur ongeveer ev<strong>en</strong> vaak voor. ✷<br />

E<strong>en</strong> paar variaties <strong>van</strong> Turingmachines<br />

In het hieronderstaande stuk over de simulatie <strong>van</strong> e<strong>en</strong> Turingmachine op e<strong>en</strong> RAM zull<strong>en</strong> we gaan beschrijv<strong>en</strong><br />

hoe e<strong>en</strong> Turingmachine met e<strong>en</strong> éénzijdig oneindige band op e<strong>en</strong> RAM kan word<strong>en</strong> gesimuleerd. We<br />

hebb<strong>en</strong> echter juist hierbov<strong>en</strong> afgesprok<strong>en</strong> dat de Turingmachineband tweezijdig oneindig is. Gelukkig is<br />

het Turingmachinemodel e<strong>en</strong> zeer vergevingsgezind model wat betreft wijziging<strong>en</strong> in de standaard. De vele<br />

bek<strong>en</strong>de variaties hebb<strong>en</strong> allemaal de eig<strong>en</strong>schap dat ze elkaars berek<strong>en</strong>ing<strong>en</strong> effici<strong>en</strong>t kunn<strong>en</strong> simuler<strong>en</strong>. We<br />

besprek<strong>en</strong> er <strong>en</strong>kele, waaronder de tweezijdige band op e<strong>en</strong> éénzijdige band. We stell<strong>en</strong> twee Turingmachines<br />

M1 <strong>en</strong> M2 in de onderstaande paragraph<strong>en</strong> voor. Hier is telk<strong>en</strong>s M1 de Turingmachine waar<strong>van</strong> e<strong>en</strong><br />

berek<strong>en</strong>ing op M2 gesimuleerd gaat word<strong>en</strong>.<br />

90<br />

��<br />

1/0/L


Meer tracks op één tape Als voorbeeld nem<strong>en</strong> we e<strong>en</strong> tape die uit twee spor<strong>en</strong> bestaat, e<strong>en</strong> bov<strong>en</strong>spoor<br />

<strong>en</strong> e<strong>en</strong> onderspoor. De toestandsovergang is nog steeds afhankelijk <strong>van</strong> de bandinhoud, maar nu word<strong>en</strong><br />

twee symbol<strong>en</strong> gelez<strong>en</strong> <strong>en</strong> geschrev<strong>en</strong>. Het is duidelijk dat elke berek<strong>en</strong>ing die op e<strong>en</strong> turingmachine met<br />

e<strong>en</strong> ééntracksband kan word<strong>en</strong> uitgevoerd in dezelfde hoeveelheid stapp<strong>en</strong> ook op e<strong>en</strong> Turingmachine met<br />

e<strong>en</strong> tweetracksband kan word<strong>en</strong> uitgevoerd. De simuler<strong>en</strong>de machine zal immers slechts één <strong>van</strong> beide<br />

tracks gebruik<strong>en</strong>. De omgekeerde bewering is ook waar. De tweetracks Turingmachine heeft e<strong>en</strong> bepaald<br />

bandalfabet Σ. Gegev<strong>en</strong> M1 bouw<strong>en</strong> we e<strong>en</strong> ééntracks Turingmachine M2 met e<strong>en</strong> groter (maar nog steeds<br />

eindig) bandalfabet Γ, zo dat Γ precies (|Σ| × |Σ| + 1/2), voor elk paar uit Σ × Σ één. We hebb<strong>en</strong> nu e<strong>en</strong><br />

codering voor elk paar symbol<strong>en</strong> uit Σ × Σ, <strong>en</strong> kunn<strong>en</strong> deze code gebruik<strong>en</strong> om het programma <strong>van</strong> M1 te<br />

vertal<strong>en</strong>.<br />

Eénzijdig oneindige band Nu we hebb<strong>en</strong> vastgesteld dat meerdere tracks op e<strong>en</strong> band op één band<br />

gesimuleerd kunn<strong>en</strong> word<strong>en</strong> kunn<strong>en</strong> we dit gebruik<strong>en</strong> om e<strong>en</strong> tweezijdig oneindige band op e<strong>en</strong> éénzijdige<br />

band te simuler<strong>en</strong>. Hiertoe marker<strong>en</strong> we het begin <strong>van</strong> de band met e<strong>en</strong> speciaal tek<strong>en</strong> <strong>en</strong> gebruik<strong>en</strong> we<br />

verder e<strong>en</strong> éénzijdig oneindige band met twee spor<strong>en</strong>. Deze tapecel zal in de simulatie niet word<strong>en</strong> gebruikt,<br />

maar alle<strong>en</strong> word<strong>en</strong> gebruikt om te zi<strong>en</strong> of in de simulatie <strong>van</strong> de berek<strong>en</strong>ing <strong>van</strong> M1 de tapekop <strong>van</strong> M1 zich<br />

links of rechts <strong>van</strong> e<strong>en</strong> speciaal aangewez<strong>en</strong> cel, die we ” de oorsprong” zull<strong>en</strong> noem<strong>en</strong> bevindt. Het bov<strong>en</strong>ste<br />

spoor stelt de linkerkant <strong>van</strong> de tweezijdig oneindige band voor terwijl het onderste spoor de rechterkant<br />

<strong>van</strong> de tweezijdig oneindige band voorstelt. De toestandsverzameling <strong>van</strong> M2 is twee keer zo groot als die<br />

<strong>van</strong> M1 om aan te gev<strong>en</strong> of de machine links <strong>van</strong> de oorsprong of rechts <strong>van</strong> de oorsprong is. Aan één <strong>van</strong><br />

beide kant<strong>en</strong> <strong>van</strong> de oorsprong (bijvoorbeeld rechts) beweegt M2 zich hetzelfde als M1 <strong>en</strong> leest <strong>en</strong> schrijft<br />

het onderste spoort. Als M1 door de oorsprong naar de linkerkant gaat, dan beweegt M2 zich steeds in<br />

teg<strong>en</strong>gestelde richting <strong>en</strong> leest <strong>en</strong> schrijft het bov<strong>en</strong>ste spoor. Zo voer<strong>en</strong> ze in ess<strong>en</strong>tie dezelfde berek<strong>en</strong>ing<br />

uit.<br />

Meer kopp<strong>en</strong> op e<strong>en</strong> band E<strong>en</strong> machine met meerdere kopp<strong>en</strong> op e<strong>en</strong> band kan meerdere symbol<strong>en</strong><br />

tegelijkertijd lez<strong>en</strong> <strong>en</strong> interpreter<strong>en</strong>. Vervolg<strong>en</strong>s kunn<strong>en</strong> de kopp<strong>en</strong> meerdere symbol<strong>en</strong> in één stap schrijv<strong>en</strong><br />

<strong>en</strong> de kopp<strong>en</strong> kunn<strong>en</strong> tegelijkertijd e<strong>en</strong> beweging naar links <strong>en</strong> naar rechts uitvoer<strong>en</strong>. Om dit te simuler<strong>en</strong><br />

rust<strong>en</strong> we M2 uit met e<strong>en</strong> band met twee spor<strong>en</strong>. In het onderste spoor houd<strong>en</strong> we de symbol<strong>en</strong> <strong>van</strong> M1 bij <strong>en</strong><br />

in het bov<strong>en</strong>ste spoor zett<strong>en</strong> we e<strong>en</strong> speciaal symbool, ∗, als we will<strong>en</strong> aangev<strong>en</strong> dat één <strong>van</strong> de gesimuleerde<br />

kopp<strong>en</strong> zich op die plaats op de band bevindt. Nu bestaat de simulatie <strong>van</strong> één berek<strong>en</strong>ingsstap op M1<br />

uit e<strong>en</strong> veeg <strong>van</strong> links naar rechts totdat alle informatie over symbol<strong>en</strong> die onder de gesimuleerde kopp<strong>en</strong><br />

verzameld is. Vervolg<strong>en</strong>s komt e<strong>en</strong> tweede update veeg, waarbij de markers(∗) naar links of naar rechts<br />

geplaatst word<strong>en</strong> <strong>en</strong> de symbol<strong>en</strong> die onder de markers stond<strong>en</strong> ver<strong>van</strong>g<strong>en</strong> word<strong>en</strong> door nieuwe.<br />

Om te lat<strong>en</strong> zi<strong>en</strong> dat deze simulatie efficiënt is, merk<strong>en</strong> we op dat de kopp<strong>en</strong> <strong>van</strong> M1 per stap niet meer<br />

dan 2 cell<strong>en</strong> verder uit elkaar kunn<strong>en</strong> kom<strong>en</strong> (één kop beweegt naar links <strong>en</strong> de andere naar rechts), <strong>en</strong> dus in<br />

n stapp<strong>en</strong> niet verder dan 2n uit elkaar kunn<strong>en</strong> kom<strong>en</strong>. Elke veeg kost dus O(n) stapp<strong>en</strong> op M2 (Misschi<strong>en</strong> is<br />

er wat locaal he<strong>en</strong> <strong>en</strong> weer geschuif nodig om de markers te updat<strong>en</strong>). Gevolg is dat simulatie <strong>van</strong> n stapp<strong>en</strong><br />

op M1 niet meer dan O(n 2 ) stapp<strong>en</strong> op M2 kan kost<strong>en</strong>.<br />

Meer band<strong>en</strong> De simulatie <strong>van</strong> meer band<strong>en</strong> op 1 band is eig<strong>en</strong>lijk dezelfde als die <strong>van</strong> meer kopp<strong>en</strong> met<br />

1 kop. Voor k band<strong>en</strong> nem<strong>en</strong> we 2k spor<strong>en</strong> <strong>en</strong> zett<strong>en</strong> op de onev<strong>en</strong> spor<strong>en</strong> (<strong>van</strong> onder<strong>en</strong> af) de symbol<strong>en</strong><br />

<strong>van</strong> M1, terwijl we op de ev<strong>en</strong> spor<strong>en</strong> markers zett<strong>en</strong> voor de plaats <strong>van</strong> de kopp<strong>en</strong>. E<strong>en</strong> paar veg<strong>en</strong> zorgt,<br />

net als in het vorige geval, voor de update <strong>van</strong> de informatie. Net als in het vorige geval is de ruimte die<br />

e<strong>en</strong> veeg moet overbrugg<strong>en</strong> ook weer begr<strong>en</strong>sd door O(n), dus kost de simulatie <strong>van</strong> n stapp<strong>en</strong> ook hier niet<br />

meer dan O(n 2 ).<br />

Tweedim<strong>en</strong>sionale band De tweedim<strong>en</strong>sionale band laat zich op de 1 dim<strong>en</strong>sionale band simuler<strong>en</strong> door<br />

e<strong>en</strong> handige nummering <strong>van</strong> de cell<strong>en</strong> <strong>van</strong> het platte vlak. Er zijn verschill<strong>en</strong>de oplossing<strong>en</strong> voor het probleem<br />

d<strong>en</strong>kbaar.<br />

91


91 90 89 88 87 86 85 84 83 82<br />

92 57 56 55 54 53 52 51 50 81<br />

93 58 31 30 29 28 27 26 49 81<br />

94 59 32 13 12 11 10 25 48 79<br />

95 60 33 14 3 2 9 24 47 78<br />

96 61 34 15 4 1 8 23 46 77<br />

97 62 35 16 5 6 7 22 45 76<br />

98 63 36 17 18 19 20 21 44 75<br />

99 64 37 38 39 40 41 42 43 74<br />

65 66 67 68 69 70 71 72 73<br />

Figuur 5.3: De spiraalmethode voor de tweedim<strong>en</strong>sionale band<br />

a t v e r o e o s e<br />

↑<br />

t a c c u s a m u s<br />

e t i u s t o o d i<br />

↑<br />

Figuur 5.4: veel band<strong>en</strong> op één band<br />

92<br />


1. We kunn<strong>en</strong> voor elke cel op M2 e<strong>en</strong> aantal aangr<strong>en</strong>z<strong>en</strong>de cell<strong>en</strong> reserver<strong>en</strong> waarin we de coordinat<strong>en</strong><br />

<strong>van</strong> deze cel in de band <strong>van</strong> M1 bijhoud<strong>en</strong>. Aangezi<strong>en</strong> deze coordinat<strong>en</strong> op M1 niet meer dan met<br />

1 per stap kunn<strong>en</strong> groei<strong>en</strong> volgt dat deze coordinat<strong>en</strong> in n stapp<strong>en</strong> niet meer dan log n tapecell<strong>en</strong> in<br />

beslag kunn<strong>en</strong> nem<strong>en</strong>, dus dat de tape <strong>van</strong> M1 niet meer dan n log n groot zal zijn. Bijgevolg kost de<br />

update per stap niet meer dan n log n. De simulatie <strong>van</strong> n stapp<strong>en</strong> kan dus in O(n 2 log n).<br />

2. We kunn<strong>en</strong> e<strong>en</strong> spiraalmethode voor de nummering <strong>van</strong> de cell<strong>en</strong> in het platte vlak bijhoud<strong>en</strong>.<br />

3. We kunn<strong>en</strong> het platte vlak onderverdeeld d<strong>en</strong>k<strong>en</strong> in strok<strong>en</strong>. Zo houd<strong>en</strong> we e<strong>en</strong> vierkant bij op de<br />

band <strong>van</strong> M2 waarin de simulatie zich afspeelt. Telk<strong>en</strong>s wanneer M1 zich buit<strong>en</strong> het vierkant begeeft,<br />

word<strong>en</strong> alle strok<strong>en</strong> met 1 cel uitgebreid.<br />

5.1.3 Simulaties tuss<strong>en</strong> RAMS <strong>en</strong> Turingmachines<br />

Turingmachines <strong>en</strong> RAMs kunn<strong>en</strong> elkaars berek<strong>en</strong>ing<strong>en</strong> uitvoer<strong>en</strong>, waarbij de overhead zowel in tijd als in<br />

geheug<strong>en</strong> begr<strong>en</strong>sd is.<br />

E<strong>en</strong> Turingmachineberek<strong>en</strong>ing op e<strong>en</strong> RAM<br />

Bij de simulatie <strong>van</strong> e<strong>en</strong> Turingmachineberek<strong>en</strong>ing op e<strong>en</strong> RAM mak<strong>en</strong> we gebruik <strong>van</strong> de indirecte adresseermogelijkheid<br />

<strong>van</strong> de RAM. De machine die we simuler<strong>en</strong> is e<strong>en</strong> éénbands Turingmachine met e<strong>en</strong> halfoneindige<br />

band. De inhoud <strong>van</strong> de cell<strong>en</strong> <strong>van</strong> de Turingmachine slaan we op in registers 1, 2, . . ., <strong>en</strong> in register 0 houd<strong>en</strong><br />

we e<strong>en</strong> getal bij dat de positie <strong>van</strong> de kop betek<strong>en</strong>t. E<strong>en</strong> beweging <strong>van</strong> de Turingmachine naar rechts simuler<strong>en</strong><br />

we door de inhoud <strong>van</strong> register 0 met 1 te verhog<strong>en</strong>, <strong>en</strong> e<strong>en</strong> beweging naar links door de inhoud <strong>van</strong><br />

het register met 1 te verlag<strong>en</strong>. De bandalfabetsymbol<strong>en</strong> word<strong>en</strong> 1 op 1 afgebeeld naar natuurlijke getall<strong>en</strong>.<br />

Het schrijv<strong>en</strong> <strong>van</strong> e<strong>en</strong> nieuw bandsymbool onder de kop kan gebeur<strong>en</strong> door e<strong>en</strong> STORE ∗0 instructie <strong>en</strong> het<br />

lez<strong>en</strong> <strong>van</strong> e<strong>en</strong> bandsymbool door e<strong>en</strong> LOAD ∗0 instructie. Verder word<strong>en</strong> toestandsovergang<strong>en</strong> gesimuleerd<br />

door kleine stukjes programma <strong>van</strong> de volg<strong>en</strong>de vorm:<br />

q : LOAD ∗0<br />

q + 1 JZERO Qi0<br />

q + 2 : SUB 1<br />

q + 3 : JZERO Qi1<br />

q + 4 : SUB 1<br />

q + 5 : JZERO Qi2<br />

q + .. : . . .<br />

q + 2k − 1 : SUB 1<br />

q + 2k : JZERO Qik−1<br />

q + 2k + 1 : JUMP Qik<br />

Als het register gelad<strong>en</strong> wordt, dan bevindt t<strong>en</strong>minste één <strong>van</strong> de k symbol<strong>en</strong> uit het bandalfabet (inclusief<br />

het blanco symbool, dat wordt gesymboliseerd door de 0, eerste instructie) zich in het register. Door het<br />

register telk<strong>en</strong>s af te lag<strong>en</strong> <strong>en</strong> naar de juiste plaats in het programma te spring<strong>en</strong> als de inhoud 0 geword<strong>en</strong> is,<br />

kunn<strong>en</strong> we e<strong>en</strong> stap <strong>van</strong> de Turingmachine simuler<strong>en</strong>. Op de overe<strong>en</strong>komstige plaats in het RAM programma<br />

wordt vervolg<strong>en</strong>s de juiste waarde met indirecte adressering in het juiste register opgeslag<strong>en</strong> <strong>en</strong> wordt tapekop<br />

beweging gesimuleerd door register 0 aan te pass<strong>en</strong>. De simulatie <strong>van</strong> e<strong>en</strong> stap <strong>van</strong> de Turingmachine kost<br />

e<strong>en</strong> constant aantal stapp<strong>en</strong> op de RAM (begr<strong>en</strong>sd door de grootte <strong>van</strong> het bandalfabet), derhalve kan de<br />

simulatie <strong>van</strong> n stapp<strong>en</strong> <strong>van</strong> de Turingmachine in O(n) stapp<strong>en</strong> op de RAM gedaan word<strong>en</strong>.<br />

E<strong>en</strong> RAM berek<strong>en</strong>ing op e<strong>en</strong> Turingmachine<br />

Bij de simulatie <strong>van</strong> de RAM op de Turingmachine, moet<strong>en</strong> we de inhoud <strong>van</strong> de registers, <strong>van</strong> de RAM<br />

opslaan op de band <strong>van</strong> de Turingmachine. We gebruik<strong>en</strong> e<strong>en</strong> driebands Turingmachine voor de simulatie.<br />

Op de eerste band houd<strong>en</strong> we de inhoud <strong>van</strong> de registers bij in de vorm ##b1b2 . . . bn#bn+1 . . . bm##,<br />

waarbij de eerste serie bits e<strong>en</strong> binaire repres<strong>en</strong>tatie is <strong>van</strong> het registeradres, <strong>en</strong> het tweede adres de inhoud<br />

93


<strong>van</strong> het register voorstelt. E<strong>en</strong> LOAD instructie is nu het kopiër<strong>en</strong> <strong>van</strong> e<strong>en</strong> gedeelte <strong>van</strong> de inhoud <strong>van</strong><br />

band 1 naar band 2, e<strong>en</strong> STORE instructie het omgekeerde, waarbij het opzoek<strong>en</strong> <strong>van</strong> het juiste adres met<br />

e<strong>en</strong> bit voor bit vergelijking kan gebeur<strong>en</strong>. De diverse vorm<strong>en</strong> <strong>van</strong> JUMPs houd<strong>en</strong> e<strong>en</strong> toestandsverandering<br />

in, de Turingmachine gaat naar het overe<strong>en</strong>komstige deel <strong>van</strong> zijn programma. ADD <strong>en</strong> SUB kunn<strong>en</strong> op<br />

e<strong>en</strong> Turingmachine word<strong>en</strong> uitgevoerd, hiervoor is e<strong>en</strong> implem<strong>en</strong>tatie <strong>van</strong> de overe<strong>en</strong>komstige algoritme in<br />

Turingmachinecode noodzakelijk, maar dit kan lineair in het aantal bits <strong>van</strong> de inhoud <strong>van</strong> het register. De<br />

duurste operatie heeft plaats wanneer aan e<strong>en</strong> register e<strong>en</strong> extra bit moet word<strong>en</strong> toegevoegd. De rest <strong>van</strong> de<br />

band moet dan word<strong>en</strong> opgeschov<strong>en</strong>. Omdat we e<strong>en</strong> extra band daarvoor hebb<strong>en</strong>, kan dit gebeur<strong>en</strong> met e<strong>en</strong><br />

aantal bewerking<strong>en</strong> dat begr<strong>en</strong>sd wordt door de l<strong>en</strong>gte <strong>van</strong> de band, het totaal aantal cell<strong>en</strong> dat in gebruik<br />

is. Om hier e<strong>en</strong> afschatting <strong>van</strong> te krijg<strong>en</strong> bed<strong>en</strong>k<strong>en</strong> we het volg<strong>en</strong>de. Het aantal registers dat in gebruik is,<br />

is natuurlijk begr<strong>en</strong>sd door het aantal stapp<strong>en</strong> dat gesimuleerd moet word<strong>en</strong>. De inhoud <strong>van</strong> de registers<br />

wordt begr<strong>en</strong>sd doordat in elke stap t<strong>en</strong> hoogste de inhoud <strong>van</strong> twee registers bij elkaar opgeteld kan word<strong>en</strong>.<br />

Aan het begin <strong>van</strong> het programma zijn de <strong>en</strong>ige aanwezige getall<strong>en</strong> de getall<strong>en</strong> die in het programma zijn<br />

opgeschrev<strong>en</strong> het grootste getal is daardoor begr<strong>en</strong>sd door één of andere constante c. In n stapp<strong>en</strong> is dus<br />

het grootste getal dat we kunn<strong>en</strong> mak<strong>en</strong> c n . Dit getal kan in O(n) bits gerepres<strong>en</strong>teerd word<strong>en</strong>.<br />

Het gevolg is dat de duurste operatie, het opschuiv<strong>en</strong> <strong>van</strong> de band, O(n) stapp<strong>en</strong> op de Turingmachine<br />

kost. Bijgevolg kunn<strong>en</strong> n operaties <strong>van</strong> de RAM in O(n 2 ) stapp<strong>en</strong> op de Turingmachine word<strong>en</strong> gesimuleerd.<br />

5.2 Onredelijke Machinemodell<strong>en</strong><br />

Dat we e<strong>en</strong> klasse <strong>van</strong> redelijke machinemodell<strong>en</strong> invoer<strong>en</strong>, doet vermoed<strong>en</strong> dat er ook e<strong>en</strong> klasse <strong>van</strong> onredelijke<br />

machinemodell<strong>en</strong> bestaat. We zull<strong>en</strong> <strong>en</strong>ige aandacht hieraan bested<strong>en</strong>, hoewel deze modell<strong>en</strong> niet in<br />

deze tekst c<strong>en</strong>traal staan.<br />

5.2.1 Onbegr<strong>en</strong>sd Parallellisme<br />

De eerste klasse <strong>van</strong> onredelijke machinemodell<strong>en</strong> is die <strong>van</strong> de machines met onbegr<strong>en</strong>sd parallellisme. De<br />

hoeveelheid hardware in het universum is begr<strong>en</strong>sd <strong>en</strong> het zou redelijk zijn te vooronderstell<strong>en</strong> dat we in<br />

polynomiaal begr<strong>en</strong>sde tijd slechts polynomiaal veel hardware aan het werk kunn<strong>en</strong> zett<strong>en</strong>. Dat ligt echter<br />

niet in het standaardmodel opgeslot<strong>en</strong>. Als we beschikk<strong>en</strong> over e<strong>en</strong> onbegr<strong>en</strong>sd aantal processor<strong>en</strong>, dan zou<br />

je je e<strong>en</strong> berek<strong>en</strong>ing kunn<strong>en</strong> voorstell<strong>en</strong> die begint met e<strong>en</strong> processor 0 die twee andere processor<strong>en</strong> aan het<br />

werk zet, in de tweede stap <strong>van</strong> de berek<strong>en</strong>ing zett<strong>en</strong> die twee andere processor<strong>en</strong> dan elk weer twee nieuwe<br />

processor<strong>en</strong> aan het werk <strong>en</strong>zovoort. In polynomiaal veel tijd kun je dan expon<strong>en</strong>tieel veel processor<strong>en</strong> aan<br />

het werk hebb<strong>en</strong>. E<strong>en</strong> Random Access Machine met deze eig<strong>en</strong>schap wordt Parallel RAM (PRAM) g<strong>en</strong>oemd.<br />

In het PRAM model hebb<strong>en</strong> alle processor<strong>en</strong> toegang tot hetzelfde werkgeheug<strong>en</strong> (de registers) <strong>en</strong> kunn<strong>en</strong><br />

ze dus in die registers waard<strong>en</strong> aan elkaar doorgev<strong>en</strong>. Zo kunn<strong>en</strong> expon<strong>en</strong>tieel veel processor<strong>en</strong> tegelijkertijd<br />

aan hetzelfde probleem gezet word<strong>en</strong>.<br />

Verderop in 7.1 zull<strong>en</strong> we e<strong>en</strong> klasse <strong>van</strong> problem<strong>en</strong> invoer<strong>en</strong> waar<strong>van</strong> het onwaarschijnlijk is dat ze in<br />

redelijke (polynomiale) tijd op e<strong>en</strong> redelijk machinemodel kunn<strong>en</strong> word<strong>en</strong> berek<strong>en</strong>d. Standaardprobleem in<br />

deze klasse is de klasse <strong>van</strong> ware boolese formules met kwantor<strong>en</strong>, QBF. De problem<strong>en</strong> in deze klasse bestaan<br />

uit proposities F (x1, . . . , xn) voorafgegaan door afwissel<strong>en</strong>de kwantor<strong>en</strong> ∃ <strong>en</strong> ∀. De vraag is voor e<strong>en</strong> gegev<strong>en</strong><br />

formule Q1x1Q2x2 . . . QnxnF (x1, . . . , xn) of zij waar is of niet. E<strong>en</strong> PRAM kan zoiets gemakkelijk uitrek<strong>en</strong><strong>en</strong>.<br />

Neem voor het gemak ev<strong>en</strong> aan dat Qi = ∃ als i ev<strong>en</strong> is <strong>en</strong> Qi = ∀ als i onev<strong>en</strong> is. Het programma <strong>van</strong><br />

processor Pi doet dan het volg<strong>en</strong>de:<br />

1. Als 2 n ≤ i ≤ 2 n+1 dan beschouwt Pi de laatste n bits <strong>van</strong> zijn index als n binaire waarheidswaard<strong>en</strong><br />

voor x1, . . . , xn. Die vult zij in in F (x1, . . . , xn) <strong>en</strong> ziet of deze toewijzing F waar maakt. Is dat het<br />

geval dan schrijft zij e<strong>en</strong> 1 in register i, <strong>en</strong> anders e<strong>en</strong> 0.<br />

2. Als i < 2 n , dan schrijft Pi de waarde −1 in registers P2i <strong>en</strong> P2i+1 <strong>en</strong> start Pi de processor<strong>en</strong> P2i <strong>en</strong><br />

P2i+1 vervolg<strong>en</strong>s leest zij elke stap registers P2i <strong>en</strong> P2i+1 uit totdat daar 0 of 1 in staat. De machine<br />

start doordat P1 deze actie uitvoert.<br />

94


3. Als i e<strong>en</strong> onev<strong>en</strong> getal is dan schrijft Pi e<strong>en</strong> 1 in register i als registers 2i <strong>en</strong> 2i + 1 allebei e<strong>en</strong> 1 krijg<strong>en</strong>,<br />

anders 0. Als i e<strong>en</strong> ev<strong>en</strong> getal is, dan schrijft Pi e<strong>en</strong> 1 in register i als t<strong>en</strong>minste één <strong>van</strong> 2i <strong>en</strong> 2(i + 1)<br />

e<strong>en</strong> één krijg<strong>en</strong>. Dwz Pi berek<strong>en</strong>t dus de ∀ resp de ∃ <strong>van</strong> de waard<strong>en</strong> <strong>van</strong> P2i <strong>en</strong> P2i+1<br />

De PRAM berek<strong>en</strong>t zo de waarde <strong>van</strong> e<strong>en</strong> QBF uit <strong>en</strong> gebruikt daarvoor ongeveer O(n) stapp<strong>en</strong>.<br />

5.2.2 Oneerlijk tell<strong>en</strong><br />

Van Random Access Machines hebb<strong>en</strong> we gezegd dat in elke cel <strong>van</strong> het geheug<strong>en</strong> e<strong>en</strong> willekeurig natuurlijk<br />

getal kan word<strong>en</strong> opgeslag<strong>en</strong>. Aangezi<strong>en</strong> er oneindig veel natuurlijke getall<strong>en</strong> bestaan is het natuurlijk<br />

onredelijk om aan te nem<strong>en</strong> dat hele grote natuurlijke getall<strong>en</strong> in één geheug<strong>en</strong>cel kunn<strong>en</strong> word<strong>en</strong> opgeslag<strong>en</strong>.<br />

In e<strong>en</strong> bandcel <strong>van</strong> e<strong>en</strong> Turingmachine kan immers maar één <strong>en</strong>kel symbool word<strong>en</strong> opgeslag<strong>en</strong>. Omdat in e<strong>en</strong><br />

polynomiaal aantal stapp<strong>en</strong> niet al te grote getall<strong>en</strong> kunn<strong>en</strong> word<strong>en</strong> gemaakt door e<strong>en</strong> RAM, is het niettemin<br />

mogelijk de berek<strong>en</strong>ing<strong>en</strong> <strong>van</strong> e<strong>en</strong> polynomiale tijd begr<strong>en</strong>sde RAM op e<strong>en</strong> polynomiale tijd begr<strong>en</strong>sde Turing<br />

machine te simuler<strong>en</strong>, zoals we hebb<strong>en</strong> gezi<strong>en</strong> in 5.1.3. Dat komt omdat e<strong>en</strong> <strong>en</strong>kele optelling niet veel meer<br />

kan do<strong>en</strong> dan e<strong>en</strong> getal verdubbel<strong>en</strong>, <strong>en</strong> verdubbel<strong>en</strong> <strong>van</strong> e<strong>en</strong> getal geeft slechts één extra bit over e<strong>en</strong> binair<br />

bandalfabet.<br />

Anders wordt de situatie als we de RAM ook lat<strong>en</strong> verm<strong>en</strong>igvuldig<strong>en</strong> <strong>en</strong> voor de verm<strong>en</strong>igvuldiging<br />

<strong>van</strong> willekeurig grote getall<strong>en</strong> slechts één operatie in rek<strong>en</strong>ing br<strong>en</strong>g<strong>en</strong>. Dan kunn<strong>en</strong> de aanwezige getall<strong>en</strong><br />

met elkaar verm<strong>en</strong>igvuldigd word<strong>en</strong> <strong>en</strong> kan in n stapp<strong>en</strong> het getal 22n gemaakt word<strong>en</strong>. Dit getal neemt<br />

expon<strong>en</strong>tiële ruimte in als het gerepres<strong>en</strong>teerd moet word<strong>en</strong> op e<strong>en</strong> Turingmachineband <strong>en</strong> derhalve kan<br />

RAM die in één stap verm<strong>en</strong>igvuldiging<strong>en</strong> <strong>van</strong> willekeurig grote getall<strong>en</strong> kan uitvoer<strong>en</strong> niet in polynomiale<br />

tijd door e<strong>en</strong> Turing machine word<strong>en</strong> gesimuleerd. Dit model <strong>van</strong> Random Access Machine noem<strong>en</strong> we<br />

Multiplication RAM of ook wel MRAM.<br />

Net als bij de PRAM wordt kan <strong>van</strong> de MRAM word<strong>en</strong> aangetoond dat deze e<strong>en</strong> berek<strong>en</strong>ing <strong>van</strong> e<strong>en</strong><br />

machine die mogelijk veel krachtiger is dan de polynomiale tijd begr<strong>en</strong>sde Turing machine kan simuler<strong>en</strong><br />

in polynomiale tijd. Het gaat om de polynomiaal geheug<strong>en</strong> begr<strong>en</strong>sde machine. E<strong>en</strong> Turing machine heeft<br />

e<strong>en</strong> accepter<strong>en</strong>de berek<strong>en</strong>ing als de initiële configuratie bij e<strong>en</strong> bepaalde invoer in minder dan expon<strong>en</strong>tieel<br />

veel stapp<strong>en</strong> e<strong>en</strong> accepter<strong>en</strong>de configuratie kan bereik<strong>en</strong>. Dit kan word<strong>en</strong> aangetoond door alle configuraties<br />

in e<strong>en</strong> matrix te schrijv<strong>en</strong> <strong>en</strong> te lat<strong>en</strong> zi<strong>en</strong> dat deze matrix wanneer hij ongeveer expon<strong>en</strong>tieel vaak met<br />

zichzelf verm<strong>en</strong>igvuldigd wordt e<strong>en</strong> 1 krijgt op de plaats die het pad <strong>van</strong> de beginconfiguratie naar de<br />

accepter<strong>en</strong>de configuratie aangeeft. E<strong>en</strong> MRAM kan zo’n matrixverm<strong>en</strong>igvuldiging in één stap do<strong>en</strong>. Omdat<br />

niet alle tuss<strong>en</strong>ligg<strong>en</strong>de matrices hoev<strong>en</strong> te word<strong>en</strong> berek<strong>en</strong>d—telk<strong>en</strong>s de gevond<strong>en</strong> matrix kwadrater<strong>en</strong> is<br />

voldo<strong>en</strong>de—hoev<strong>en</strong> er niet expon<strong>en</strong>tieel veel verm<strong>en</strong>igvuldiging<strong>en</strong> gedaan word<strong>en</strong> (de matrix moet nog wel<br />

als één getal in e<strong>en</strong> register word<strong>en</strong> voorgesteld, <strong>en</strong> matrixverm<strong>en</strong>igvuldiging moet nog word<strong>en</strong> aangepast,<br />

maar dat zijn details), maar slechts polynomiaal veel. Details <strong>van</strong> dit bewijs zijn, zoals de lezer zich misschi<strong>en</strong><br />

kan voorstell<strong>en</strong>, behoorlijk ingewikkeld (zie [HS76]).<br />

Voor zowel de MRAM als de PRAM is het onbek<strong>en</strong>d of er ook werkelijk e<strong>en</strong> probleem is dat door<br />

e<strong>en</strong> MRAM kan word<strong>en</strong> opgelost (taal die kan word<strong>en</strong> herk<strong>en</strong>d) dat niet in polynomiale tijd door e<strong>en</strong><br />

Turing machine kan word<strong>en</strong> opgelost. Immers, voor e<strong>en</strong> verm<strong>en</strong>igvuldiging kan e<strong>en</strong> recursieve procedure<br />

word<strong>en</strong> opgeschrev<strong>en</strong> waar<strong>van</strong> de te bewerk<strong>en</strong> onderdel<strong>en</strong> slechts half zo groot zijn als de oorspronkelijke. In<br />

polynomiaal veel recursieve stapp<strong>en</strong> kunn<strong>en</strong> dus expon<strong>en</strong>tieel grote getall<strong>en</strong> word<strong>en</strong> opgeknipt tot onderdel<strong>en</strong><br />

<strong>van</strong> l<strong>en</strong>gte 1 die dan gemakkelijk ook op e<strong>en</strong> Turingmachine met elkaar verm<strong>en</strong>igvuldigd kunn<strong>en</strong> word<strong>en</strong>.<br />

In totaal kan het geheug<strong>en</strong>gebruik word<strong>en</strong> beperkt tot polynomiale afmeting<strong>en</strong>, omdat de stukk<strong>en</strong> kort<br />

zijn <strong>en</strong> de recursiediepte beperkt. Het is dus niet op voorhand uitgeslot<strong>en</strong> dat de berek<strong>en</strong>ing <strong>van</strong> e<strong>en</strong><br />

MRAM kan word<strong>en</strong> gesimuleerd door e<strong>en</strong> Turingmachine in polynomiaal geheug<strong>en</strong>. Omdat het probleem of<br />

polynomiaal geheug<strong>en</strong>begr<strong>en</strong>sde Turingmachines gesimuleerd kunn<strong>en</strong> word<strong>en</strong> door polynomiale tijdbegr<strong>en</strong>sde<br />

Turingmachines nog steeds op<strong>en</strong> is, kunn<strong>en</strong> we dus ook niet zonder meer zegg<strong>en</strong> dat de MRAM e<strong>en</strong> onredelijk<br />

machinemodel is.<br />

95


5.2.3 Somm<strong>en</strong><br />

1. Pas het programma <strong>van</strong> de Turingmachine uit voorbeeld 5.1.2 zo aan dat het werkt op e<strong>en</strong> machine<br />

met half-oneindige band.<br />

2. Hoeveel kost de simulatie <strong>van</strong> één stap <strong>van</strong> machine M1 die e<strong>en</strong> tweedim<strong>en</strong>sionale band heeft op machine<br />

M2 als we de spiraalmethode <strong>van</strong> nummering <strong>van</strong> cell<strong>en</strong> gebruik<strong>en</strong>? Wat als we de strok<strong>en</strong>zaagmethode<br />

gebruik<strong>en</strong> (in dit geval is e<strong>en</strong> analyse <strong>van</strong> de uitgesmeerde complexiteit aan de orde).<br />

3. E<strong>en</strong> EDIT RAM is e<strong>en</strong> random access machine die kan werk<strong>en</strong> met textfiles <strong>en</strong> de volg<strong>en</strong>de operaties<br />

heeft:<br />

(a) E<strong>en</strong> symbool uit e<strong>en</strong> file lez<strong>en</strong> bij e<strong>en</strong> textpointer (cursor)<br />

(b) E<strong>en</strong> symbool in e<strong>en</strong> file schrijv<strong>en</strong> op de plaats <strong>van</strong> e<strong>en</strong> textpointer<br />

(c) E<strong>en</strong> texpointer aan het einde <strong>van</strong> e<strong>en</strong> file schrijv<strong>en</strong><br />

(d) E<strong>en</strong> texpointer op e<strong>en</strong> plaats in de file zett<strong>en</strong> die overe<strong>en</strong>komt met e<strong>en</strong> getal in e<strong>en</strong> register<br />

(e) Ver<strong>van</strong>g<strong>en</strong> <strong>van</strong> text1 door text2 overal tegelijkertijd in e<strong>en</strong> file<br />

(f) Aan elkaar plakk<strong>en</strong> <strong>van</strong> files<br />

(g) Del<strong>en</strong> <strong>van</strong> textfiles copiër<strong>en</strong> aan de hand <strong>van</strong> de positie <strong>van</strong> textpointers<br />

(h) Del<strong>en</strong> <strong>van</strong> files verwijder<strong>en</strong> die door de positie <strong>van</strong> textpointers bepaald word<strong>en</strong>.<br />

Al deze operaties kunn<strong>en</strong> in één stap door de Edit-RAM gedaan word<strong>en</strong>. Laat zi<strong>en</strong> dat de Edit-RAM<br />

in polynomiale tijd de waarheid <strong>van</strong> e<strong>en</strong> QBF kan bepal<strong>en</strong>.<br />

96


Hoofdstuk 6<br />

C<strong>en</strong>trale <strong>Complexiteit</strong>sklass<strong>en</strong><br />

Alle redelijke machinemodell<strong>en</strong> kunn<strong>en</strong> elkaar simuler<strong>en</strong> in Polynomiale Tijd, is onze c<strong>en</strong>trale aanname waar<br />

het machinemodell<strong>en</strong> betreft. Als we dus uitsprak<strong>en</strong> will<strong>en</strong> do<strong>en</strong> over problem<strong>en</strong> <strong>en</strong> de complexiteitsklass<strong>en</strong><br />

waar ze in thuis hor<strong>en</strong>, dan zull<strong>en</strong> we in ieder geval alle problem<strong>en</strong> die in complexiteit niet meer dan e<strong>en</strong><br />

polynoom verschill<strong>en</strong> in dezelfde complexiteitsklasse moet<strong>en</strong> plaats<strong>en</strong>. Deze complexiteitsklasse noem<strong>en</strong><br />

we P. De klasse P zal als het ware de 0 vorm<strong>en</strong> <strong>van</strong> onze voorlopige hierarchie <strong>van</strong> complexiteitsklass<strong>en</strong>.<br />

E<strong>en</strong> plafond zull<strong>en</strong> we vooralsnog niet definiër<strong>en</strong>, maar om e<strong>en</strong> speelbaar veld <strong>van</strong> complexiteitsklass<strong>en</strong> te<br />

verkrijg<strong>en</strong> zull<strong>en</strong> we minst<strong>en</strong>s moet<strong>en</strong> zi<strong>en</strong> dat er e<strong>en</strong> complexiteitsklasse bestaat die niet gelijk is aan P.<br />

In Hoofdstuk 1 <strong>van</strong> Deel I maakt<strong>en</strong> wij onderscheid tuss<strong>en</strong> problem<strong>en</strong> waarvoor polynomiaal begr<strong>en</strong>sde<br />

algoritm<strong>en</strong> bestaan <strong>en</strong> problem<strong>en</strong> waarvoor alle<strong>en</strong> expon<strong>en</strong>tiële tijd begr<strong>en</strong>sde algoritm<strong>en</strong> bek<strong>en</strong>d zijn. Dat<br />

was uiteraard niet toevallig. We zull<strong>en</strong> zi<strong>en</strong> dat de klasse <strong>van</strong> problem<strong>en</strong> waarvoor alle<strong>en</strong> expon<strong>en</strong>tiële<br />

tijd begr<strong>en</strong>sde algoritm<strong>en</strong> bek<strong>en</strong>d zijn, die we EXP zull<strong>en</strong> noem<strong>en</strong>, ook problem<strong>en</strong> bevat waarvoor ge<strong>en</strong><br />

polynomiale tijd begr<strong>en</strong>sde algoritm<strong>en</strong> bestaan <strong>en</strong> dus dat deze klasse werkelijk verschilt <strong>van</strong> de klasse P.<br />

Als machinemodel nem<strong>en</strong> we de Turingmachine. Er zijn twee duidelijke complexiteitsmat<strong>en</strong> aan e<strong>en</strong><br />

Turingmachineberek<strong>en</strong>ing te gev<strong>en</strong>, tijd <strong>en</strong> geheug<strong>en</strong>. E<strong>en</strong> variant <strong>van</strong> de Turingmachine, de zog<strong>en</strong>oemde<br />

nondetermistische Turingmachine zal verderop in het verhaal ook e<strong>en</strong> rol spel<strong>en</strong>. Bij e<strong>en</strong> nondeterministische<br />

Turingmachine is er ge<strong>en</strong> sprake <strong>van</strong> e<strong>en</strong> toestandsovergangsfunctie, maar <strong>van</strong> e<strong>en</strong> toestandsovergangsrelatie.<br />

Bij e<strong>en</strong> bepaalde configuratie zijn er meerdere vervolgconfiguraties mogelijk. E<strong>en</strong> nondeterministische<br />

Turingmachine heeft op e<strong>en</strong> bepaalde invoer meerdere mogelijke berek<strong>en</strong>ing<strong>en</strong>. We sprek<strong>en</strong> af dat e<strong>en</strong> nondeterministische<br />

Turingmachine de invoer x accepteert als er e<strong>en</strong> berek<strong>en</strong>ing op x mogelijk is die accepteert.<br />

Dit heeft het voordeel dat we expressies als (∃x)[P (x)] met e<strong>en</strong> algoritmisch model kunn<strong>en</strong> repres<strong>en</strong>ter<strong>en</strong>.<br />

Vele vrag<strong>en</strong> uit de AI, bijvoorbeeld de vraag of er e<strong>en</strong> pad is waarlangs de robot <strong>van</strong> A naar B kan kom<strong>en</strong>,<br />

kunn<strong>en</strong> dan als algoritmisch probleem word<strong>en</strong> gesteld. Doorgaans is dan de nondeterministische algoritme<br />

<strong>van</strong> geringe complexiteit. Er hoeft alle<strong>en</strong> aangetoond te word<strong>en</strong> dat de oplossing bestaat gegev<strong>en</strong> de oplossing.<br />

Dat voor het vind<strong>en</strong> <strong>van</strong> de oplossing vaak niets beters te vind<strong>en</strong> is dan exhaustive search is er de<br />

oorzaak <strong>van</strong> vele interessante onderzoeksgebied<strong>en</strong> in de AI.<br />

Het verband tuss<strong>en</strong> tijd <strong>en</strong> geheug<strong>en</strong> is bijzonder interessant. Vaak kunn<strong>en</strong> we door wat meer geheug<strong>en</strong> te<br />

gebruik<strong>en</strong> (bijvoorbeeld bij zoek<strong>en</strong> <strong>en</strong> sorter<strong>en</strong>) belangrijke tijdwinst boek<strong>en</strong>. Geheug<strong>en</strong> is echter ook duurder<br />

dan tijd. Tijd krijg je <strong>van</strong>zelf meer door te wacht<strong>en</strong>. Geheug<strong>en</strong> moet je gaan kop<strong>en</strong>. Teg<strong>en</strong>woordig hebb<strong>en</strong><br />

we vaak de beschikking over hoeveelhed<strong>en</strong> geheug<strong>en</strong> waar<strong>van</strong> we vroeger slechts kond<strong>en</strong> drom<strong>en</strong>. Databases<br />

<strong>van</strong> meer dan e<strong>en</strong> petabyte zijn ge<strong>en</strong> uitzondering meer <strong>en</strong> schijv<strong>en</strong> <strong>van</strong> terabytes zijn zo langzamerhand<br />

retail artikel<strong>en</strong>. Op zoveel detail zull<strong>en</strong> we hier echter niet ingaan. We zull<strong>en</strong> net als met tijd ook de<br />

geheug<strong>en</strong>complexiteit beschouw<strong>en</strong> als functie <strong>van</strong> de l<strong>en</strong>gte <strong>van</strong> de invoer. Polynomiaal geheug<strong>en</strong> wordt dan<br />

aangegev<strong>en</strong> met PSPACE. Ook hier is e<strong>en</strong> nondeterministische variant, maar in 7.2 zull<strong>en</strong> we de opmerkelijke<br />

stelling teg<strong>en</strong>kom<strong>en</strong> dat voor geheug<strong>en</strong>gebruik het nondeterministische model ge<strong>en</strong> extra rek<strong>en</strong>kracht geeft.<br />

Het is duidelijk dat e<strong>en</strong> gr<strong>en</strong>s op het geheug<strong>en</strong> liberaler is dan e<strong>en</strong> zelfde gr<strong>en</strong>s op de tijd. Immers in één stap<br />

kunn<strong>en</strong> we niet meer dan één nieuwe geheug<strong>en</strong>cel aansprek<strong>en</strong>. Derhalve kunn<strong>en</strong> we in polynomiaal geheug<strong>en</strong><br />

altijd minst<strong>en</strong>s ev<strong>en</strong>veel als in polynomiale tijd. Aan de andere kant heeft e<strong>en</strong> Turingmachine, omdat<br />

97


deze e<strong>en</strong> eindig aantal toestand<strong>en</strong>, <strong>en</strong> e<strong>en</strong> eindig alfabet heeft niet meer dan expon<strong>en</strong>tieel veel verschill<strong>en</strong>de<br />

configuraties op e<strong>en</strong> bepaalde geheug<strong>en</strong>gr<strong>en</strong>s. Vandaar dat in expon<strong>en</strong>tiële tijd minst<strong>en</strong>s net zoveel gedaan<br />

kan word<strong>en</strong> als in polynomiaal geheug<strong>en</strong>.<br />

Vanwege de simulatie <strong>van</strong> machinemodell<strong>en</strong> is wat betreft geheug<strong>en</strong>complexiteit logarithmisch geheug<strong>en</strong><br />

de kleinste maat die onafhankelijk <strong>van</strong> het machinemodel gepres<strong>en</strong>teerd kan word<strong>en</strong>. <strong>Complexiteit</strong>sklass<strong>en</strong><br />

die e<strong>en</strong> c<strong>en</strong>trale rol spel<strong>en</strong> noter<strong>en</strong> we in Figuur 6.1 in oplop<strong>en</strong>de volgorde <strong>van</strong> inclusie. De klasse volg<strong>en</strong>d op<br />

deze hierarchy is PRIM, de klasse <strong>van</strong> primitief recursieve functies, waarin tijd <strong>en</strong> geheug<strong>en</strong>gr<strong>en</strong>z<strong>en</strong> word<strong>en</strong><br />

losgelat<strong>en</strong>.<br />

LOGSPACE logaritmisch begr<strong>en</strong>sd geheug<strong>en</strong><br />

NLOGSPACE nondeterministisch logaritmisch begr<strong>en</strong>sd geheug<strong>en</strong><br />

P polynomiaal begr<strong>en</strong>sde tijd<br />

NP nondeterministisch polynomiaal begr<strong>en</strong>sde tijd<br />

PSPACE polynomiaal begr<strong>en</strong>sd geheug<strong>en</strong><br />

EXP expon<strong>en</strong>tieel begr<strong>en</strong>sde tijd<br />

NEXP nondetermistisch expon<strong>en</strong>tieel begr<strong>en</strong>sde tijd<br />

EXPSPACE expon<strong>en</strong>tieel begr<strong>en</strong>sd geheug<strong>en</strong><br />

DEXP dubelexpon<strong>en</strong>tieel begr<strong>en</strong>sde tijd (22p(n) )<br />

.<br />

ELEMENTARY tijd begr<strong>en</strong>sd door 2 22···<br />

� �� �<br />

n<br />

.<br />

Figuur 6.1: <strong>Complexiteit</strong>sklass<strong>en</strong><br />

6.1 Polynomiale <strong>en</strong> Expon<strong>en</strong>tiële Tijd<br />

Om aan te ton<strong>en</strong> dat er problem<strong>en</strong> zijn die wel in expon<strong>en</strong>tiële tijd op te loss<strong>en</strong> zijn, maar niet in polynomiale<br />

tijd, moet<strong>en</strong> we t<strong>en</strong>minste één probleem definiër<strong>en</strong> dat op ge<strong>en</strong> <strong>en</strong>kele machine in polynomiale tijd is op te<br />

loss<strong>en</strong>. Weg<strong>en</strong>s onze aanname dat redelijke machines elkaar in polynomiale tijd kunn<strong>en</strong> simuler<strong>en</strong>, zijn we in<br />

de gelukkige omstandigheid dat we dat alle<strong>en</strong> maar voor Turing machines hoev<strong>en</strong> te do<strong>en</strong>. Dan nog hebb<strong>en</strong><br />

we e<strong>en</strong> probleem. Er bestaan oneindig veel Turing machines <strong>en</strong> er bestaan oneindig veel polynom<strong>en</strong>, dus hoe<br />

mak<strong>en</strong> we e<strong>en</strong> probleem dat door ge<strong>en</strong> <strong>van</strong> die oneindig veel Turing machines in tijd begr<strong>en</strong>sd door één <strong>van</strong><br />

die polynom<strong>en</strong> kan word<strong>en</strong> opgelost? De oplossing hiervoor is codering, of ” de Universele Turing Machine”.<br />

We mak<strong>en</strong> e<strong>en</strong> Turing machine die elke andere Turing machine kan simuler<strong>en</strong> in tijd begr<strong>en</strong>sd door e<strong>en</strong><br />

polynoom in de tijd waarin de te simuler<strong>en</strong> machine de berek<strong>en</strong>ing volooit. Dan hoev<strong>en</strong> we alle<strong>en</strong> nog maar<br />

e<strong>en</strong> probleem te verzinn<strong>en</strong> dat voor ge<strong>en</strong> <strong>en</strong>kel polynoom p in tijd begr<strong>en</strong>sd door p op die universele machine<br />

kan word<strong>en</strong> opgelost, <strong>en</strong> we zijn klaar.<br />

6.1.1 De Universele Turing Machine<br />

Zoals we in 5.1.2 hebb<strong>en</strong> gezi<strong>en</strong> kunn<strong>en</strong> we e<strong>en</strong> Turing machine programma dat bestaat uit e<strong>en</strong> verzameling<br />

toestand<strong>en</strong> Q <strong>en</strong> e<strong>en</strong> toestandsovergangsfunctie δ beschrijv<strong>en</strong> door e<strong>en</strong> opsomming <strong>van</strong> de vorm<br />

〈q0, a, q1, b, R〉 . . . te gev<strong>en</strong>. We zull<strong>en</strong> deze opsomming coder<strong>en</strong> als lijst getall<strong>en</strong> die straks door onze universele<br />

machine gebruikt kan word<strong>en</strong> om de berek<strong>en</strong>ing gedaan door deze machine na te spel<strong>en</strong>. Dus, laat<br />

de toestands verzameling Q = {q0, . . . , qk} zijn <strong>en</strong> het bandalfabet {0, 1, B}. We coder<strong>en</strong> L als 0, <strong>en</strong> R als<br />

1. Voor natuurlijk getal i, laat bin(i) de binaire repres<strong>en</strong>tatie <strong>van</strong> i zijn. E<strong>en</strong> instructie qi, a → qj, b, R, met<br />

a, b ∈ {0, 1, 2}, waarin 2 de repres<strong>en</strong>tatie <strong>van</strong> het blanco symbool is, kan dan bijvoorbeeld geschrev<strong>en</strong> word<strong>en</strong><br />

als bin(i)#a#bin(j)#b#1. Als we elke instructie inst, op deze manier naar e<strong>en</strong> repres<strong>en</strong>tatie rep(inst)<br />

vertal<strong>en</strong> in het alfabet {0, 1, #} dan kunn<strong>en</strong> we het hele programma schrijv<strong>en</strong> als rep(inst1)# . . . repinstn#.<br />

Tot slot kunn<strong>en</strong> we elke 0 ver<strong>van</strong>g<strong>en</strong> door 00, elke 1 door 11 <strong>en</strong> elke # door 01 <strong>en</strong> e<strong>en</strong> 1 voor de hele codering<br />

98


zett<strong>en</strong> om e<strong>en</strong> éénduidige afbeelding <strong>van</strong> Turing machines in de natuurlijke getall<strong>en</strong> te krijg<strong>en</strong>. Om <strong>van</strong><br />

deze repres<strong>en</strong>tatie e<strong>en</strong> bijectie te mak<strong>en</strong> sprek<strong>en</strong> we af dat binair geschrev<strong>en</strong> natuurlijke getall<strong>en</strong> die niet, als<br />

hierbov<strong>en</strong> beschrev<strong>en</strong>, e<strong>en</strong> zinvol Turing machine programma coder<strong>en</strong> altijd e<strong>en</strong> Turing machine programma<br />

coder<strong>en</strong> dat de lege verzameling herk<strong>en</strong>t. Ook de invoer <strong>van</strong> e<strong>en</strong> Turing machine kan op deze manier word<strong>en</strong><br />

meeg<strong>en</strong>om<strong>en</strong>. E<strong>en</strong> repres<strong>en</strong>tatie rep(prog) <strong>van</strong> e<strong>en</strong> Turing machine programma als bov<strong>en</strong> beschrev<strong>en</strong> kan met<br />

e<strong>en</strong> natuurlijk getal i gecombineerd word<strong>en</strong> asl rep(prog)###bin(i). Opnieuw vertal<strong>en</strong> we 0 naar 00, 1 naar<br />

11 <strong>en</strong> # naar 01 <strong>en</strong> krijg<strong>en</strong> zo e<strong>en</strong> repres<strong>en</strong>tatie in de binaire getall<strong>en</strong> <strong>van</strong> de par<strong>en</strong> programma,invoer. E<strong>en</strong><br />

Turing machine, die we de universele Turing machine noem<strong>en</strong>, kan als zij e<strong>en</strong> getal als invoer op de band<br />

aantreft, dit getal op de hier beschrev<strong>en</strong> manier interpreter<strong>en</strong> als paar (programma, invoer), <strong>en</strong> het aldus<br />

beschrev<strong>en</strong> programma op de invoer simuler<strong>en</strong>.<br />

Voorbeeld 6.1.1: Als voorbeeld vertal<strong>en</strong> we het programma uit Voorbeeld 5.1.2 naar e<strong>en</strong> binaire string.<br />

De toestandsovergangsfunctie zag er als volgt uit.<br />

δ(q0, 1) = 〈q1, 1, R〉<br />

δ(q0, B) = 〈qF , 1, R〉<br />

δ(q1, 0) = 〈q1, 0, R〉<br />

δ(q1, 1) = 〈q1, 1, R〉<br />

δ(q1, B) = 〈q2, B, L〉<br />

δ(q2, 0) = 〈qF , 1, L〉<br />

δ(q2, 1) = 〈q2, 0, L〉<br />

δ(q2, B) = 〈qF , 1, L〉<br />

We hebb<strong>en</strong> te mak<strong>en</strong> met vier toestand<strong>en</strong>. Deze krijg<strong>en</strong> repres<strong>en</strong>taties bin(0), bin(1), bin(2) <strong>en</strong> bin(3):<br />

00, 01, 10 <strong>en</strong> 11. Het bandalfabet is {0, 1, B}, wat we coder<strong>en</strong> als: 00, 01 <strong>en</strong> 10. De beweging<strong>en</strong> L <strong>en</strong> R<br />

coder<strong>en</strong> we vervolg<strong>en</strong>s als 0 <strong>en</strong> 1. De instructies zi<strong>en</strong> er na deze codering<strong>en</strong> uit als:<br />

00#01#01#01#1 δ(q0, 1) = 〈q1, 1, R〉<br />

00#10#11#01#1 δ(q0, B) = 〈qF , 1, R〉<br />

01#00#01#00#1 δ(q1, 0) = 〈q1, 0, R〉<br />

01#01#01#01#1 δ(q1, 1) = 〈q1, 1, R〉<br />

01#10#10#10#0 δ(q1, B) = 〈q2, B, L〉<br />

10#00#11#01#0 δ(q2, 0) = 〈qF , 1, L〉<br />

10#01#10#00#0 δ(q2, 1) = 〈q2, 0, L〉<br />

10#11#11#01#0 δ(q2, B) = 〈qF , 1, L〉<br />

Nu schrijv<strong>en</strong> we alle instructies achter elkaar <strong>en</strong> krijg<strong>en</strong> de string:<br />

00#01#01#01#1#00#10#11#01#1#01#00#01#00#1#01#01#01#01#1<br />

01#10#10#10#0#10#00#11#01#0#10#01#10#00#0#10#11#11#01#0<br />

die we kunn<strong>en</strong> vertal<strong>en</strong> naar de binaire rij:<br />

000001001101001101001101110100000111000111110100110111010011<br />

01000001001101000001110100110100110100110100110111<br />

0011011100011100011100010001110001000001111101001101<br />

0001110001001101110001000001000111000111110111110100110100<br />

✷<br />

Ook begr<strong>en</strong>sde berek<strong>en</strong>ing<strong>en</strong> kunn<strong>en</strong> op e<strong>en</strong> dergelijke manier door de universele Turing machine word<strong>en</strong><br />

uitgevoerd. Als de Turing machine door één of andere functie f in tijd begr<strong>en</strong>sd wordt, dan kunn<strong>en</strong> we deze<br />

functie meecoder<strong>en</strong> door in plaats <strong>van</strong> het paar programma#invoer het drietal programma#invoer#f als<br />

getal te coder<strong>en</strong>, mits er voor f e<strong>en</strong> efficiënte codering bestaat. In het geval dat f e<strong>en</strong> polynoom is, dan is<br />

alle<strong>en</strong> het rijtje coëfficiënt<strong>en</strong> <strong>van</strong> de macht<strong>en</strong> <strong>van</strong> x nodig om het polynoom éénduidig vast te legg<strong>en</strong>. De<br />

universele Turing machine kan in dat geval beginn<strong>en</strong> met f(|x|) uit te rek<strong>en</strong><strong>en</strong> op e<strong>en</strong> aparte band <strong>en</strong> dit<br />

99


getal na elke gesimuleerde stap met 1 aflag<strong>en</strong>. Als dit getal gelijk wordt aan 0, is de gesimuleerde berek<strong>en</strong>ing<br />

geëindigd. We sprek<strong>en</strong> af dat, als de Turing machine bij het bereik<strong>en</strong> <strong>van</strong> de 0 op de tijdband nog niet<br />

geaccepteerd heeft, de invoer wordt verworp<strong>en</strong>. Op deze manier krijg<strong>en</strong> we geklokte Turing machines. Het<br />

is duidelijk dat er bij hanter<strong>en</strong> <strong>van</strong> geschikte tijdgr<strong>en</strong>z<strong>en</strong>, ge<strong>en</strong> verschil bestaat in de complexiteitsklass<strong>en</strong><br />

gedefinieerd door geklokte Turing machines <strong>en</strong> tijdbegr<strong>en</strong>sde Turing machines. Kijk bijvoorbeeld naar de<br />

klasse P. Voor elke taal in P is er e<strong>en</strong> geklokte machine die deze taal herk<strong>en</strong>t. Immers er is e<strong>en</strong> polynomiaal,<br />

begr<strong>en</strong>sde machine die die taal herk<strong>en</strong>t. Laat p(n) de tijdgr<strong>en</strong>s zijn. Als we zo’n machine nem<strong>en</strong> <strong>en</strong> hem<br />

p(n) of groter begr<strong>en</strong>z<strong>en</strong> hebb<strong>en</strong> we de gew<strong>en</strong>ste geklokte machine. Omgekeerd is het evid<strong>en</strong>t dat elke p(n)<br />

geklokte Turing machine e<strong>en</strong> taal in P herk<strong>en</strong>t.<br />

Deze codering <strong>en</strong> simulatie is e<strong>en</strong> stap die we moet<strong>en</strong> beschrijv<strong>en</strong> voor het volg<strong>en</strong>de onderwerp, maar<br />

is ook e<strong>en</strong> stap waaraan de informaticus natuurlijk al lang gew<strong>en</strong>d is. Elk programma dat de informaticus<br />

schrijft wordt in de machine (bijvoorbeeld door de compiler) gerepres<strong>en</strong>teerd als e<strong>en</strong> lange aane<strong>en</strong>geslot<strong>en</strong><br />

binaire rij <strong>en</strong> dus als e<strong>en</strong> getal. Het aantal manier<strong>en</strong> waarop dit kan gebeur<strong>en</strong> is groot. Het is zelfs d<strong>en</strong>kbaar<br />

e<strong>en</strong> programma te repres<strong>en</strong>ter<strong>en</strong> als e<strong>en</strong> rij met daarin maar één symbool, zo’n repres<strong>en</strong>tatie noem<strong>en</strong> we<br />

e<strong>en</strong> tally repres<strong>en</strong>tatie. Echter, de tally repres<strong>en</strong>tatie heeft als nadeel dat ze expon<strong>en</strong>tieel langer is dan<br />

repres<strong>en</strong>taties waarin meer dan 1 symbool gebruikt wordt, terwijl deze laatste repres<strong>en</strong>taties onderling niet<br />

meer dan e<strong>en</strong> constante factor <strong>van</strong> elkaar in l<strong>en</strong>gte verschill<strong>en</strong>.<br />

6.1.2 Het Padding Lemma<br />

In de vorige sectie hebb<strong>en</strong> we lat<strong>en</strong> zi<strong>en</strong> dat er e<strong>en</strong> 1 − 1-relatie bestaat tuss<strong>en</strong> Turingmachine programma’s<br />

<strong>en</strong> binair geschrev<strong>en</strong> natuurlijke getall<strong>en</strong>. Er bestaat uiteraard ook e<strong>en</strong> 1 − 1 relatie tuss<strong>en</strong> Turing machine<br />

programma’s <strong>en</strong> functies <strong>van</strong> de natuurlijke getall<strong>en</strong> naar {0, 1} door te zegg<strong>en</strong> dat het resultaat <strong>van</strong> de<br />

berek<strong>en</strong>ing 1 is dan <strong>en</strong> slechts dan als de Turing machine eindigt in e<strong>en</strong> accepter<strong>en</strong>de toestand (of überhaupt<br />

eindigt) <strong>en</strong> anders 0. Elke functie naar {0, 1} is de repres<strong>en</strong>tatie <strong>van</strong> e<strong>en</strong> deelverzameling <strong>van</strong> het origineel<br />

<strong>van</strong> die functie. Als het origineel e<strong>en</strong> verzameling strings is, dan repres<strong>en</strong>teert zo’n functie e<strong>en</strong> taal, door te<br />

zegg<strong>en</strong> dat alles wat afgebeeld wordt op 1 in de taal zit, <strong>en</strong> alles wat afgebeeld wordt op 0 niet in de taal<br />

zit. Zo kan dus elk natuurlijk getal e<strong>en</strong> taal of e<strong>en</strong> probleem repres<strong>en</strong>ter<strong>en</strong>. Deze repres<strong>en</strong>tatie is echter zeer<br />

redundant. Elke taal wordt door oneindig veel Turing machine programma’s gerepres<strong>en</strong>teerd. Immers, stel<br />

dat programma prog e<strong>en</strong> taal L repres<strong>en</strong>teert, dan wordt L ook gerepres<strong>en</strong>teerd door programma prog#bin(i)<br />

voor elk natuurlijk getal i. Deze observatie, die in de berek<strong>en</strong>baarheidstheorie bek<strong>en</strong>d staat als het Padding<br />

Lemma, is e<strong>en</strong> belangrijk hulpmiddel bij e<strong>en</strong> belangrijke techniek om complexiteitsklass<strong>en</strong> te scheid<strong>en</strong>, de<br />

diagnonalisatie.<br />

6.1.3 P �= EXP<br />

Om aan te ton<strong>en</strong> dat EXP werkelijk verschilt <strong>van</strong> P zull<strong>en</strong> we e<strong>en</strong> taal mak<strong>en</strong> die door e<strong>en</strong> Turing machine M<br />

in expon<strong>en</strong>tiële tijd herk<strong>en</strong>d wordt, maar die door ge<strong>en</strong> <strong>en</strong>kele Turing machine in polynomiale tijd herk<strong>en</strong>d<br />

kan word<strong>en</strong>. Hiervoor is het handig dat we in de vorige subsectie hebb<strong>en</strong> aangetoond dat er e<strong>en</strong> 1-1 verband<br />

bestaat tuss<strong>en</strong> Turing machines <strong>en</strong> natuurlijke getall<strong>en</strong>, tuss<strong>en</strong> par<strong>en</strong> Turing machines-input <strong>en</strong> natuurlijke<br />

getall<strong>en</strong> <strong>en</strong> zelfs tuss<strong>en</strong> drietall<strong>en</strong> Turing machine-input-polynoom <strong>en</strong> natuurlijke getall<strong>en</strong>, m.a.w. dat we elk<br />

natuurlijk getal kunn<strong>en</strong> interpreter<strong>en</strong> als e<strong>en</strong> drietal, Turing machine, invoer, polynoom <strong>en</strong> vervolg<strong>en</strong>s de<br />

executie <strong>van</strong> die Turing machine op die invoer voor e<strong>en</strong> aantal stapp<strong>en</strong> begr<strong>en</strong>sd door dat polynoom kunn<strong>en</strong><br />

simuler<strong>en</strong>. Aangezi<strong>en</strong> elk drietal is af te beeld<strong>en</strong> op e<strong>en</strong> natuurlijk getal krijg<strong>en</strong> we door alle getall<strong>en</strong> als<br />

invoer te bekijk<strong>en</strong> e<strong>en</strong> opsomming <strong>van</strong> alle tal<strong>en</strong> in P, c.q. <strong>van</strong> machines die e<strong>en</strong> taal herk<strong>en</strong>n<strong>en</strong>. De techniek<br />

die we hiervoor gebruik<strong>en</strong> is die <strong>van</strong> de diagonalisatie, voor het eerst gebruikt door G. Cantor. Cantor bewees<br />

dat er meer reële getall<strong>en</strong> zijn dan natuurlijke getall<strong>en</strong> als volgt. Neem aan dat er net zoveel reële getall<strong>en</strong><br />

als natuurlijke getall<strong>en</strong> zijn. Dan kun je de reële getall<strong>en</strong> tuss<strong>en</strong> 0 <strong>en</strong> 1 op volgorde zett<strong>en</strong> (zie figuur 6.2).<br />

Die reële getall<strong>en</strong> kun je voorstell<strong>en</strong> door e<strong>en</strong> decimale punt gevolgd door e<strong>en</strong> oneindige rij null<strong>en</strong> <strong>en</strong> e<strong>en</strong><strong>en</strong><br />

(e<strong>en</strong> binaire breuk). Nu kan ik e<strong>en</strong> nieuw getal mak<strong>en</strong> door langs de diagonaal <strong>van</strong> die opsomming te lop<strong>en</strong><br />

<strong>en</strong> overal waar e<strong>en</strong> 0 staat e<strong>en</strong> 1 noter<strong>en</strong> <strong>en</strong> omgekeerd. Mijn nieuwe getal krijgt dus e<strong>en</strong> 1 op plaats i als er<br />

e<strong>en</strong> 0 op plaats (i, i) staat in de opsomming <strong>en</strong> e<strong>en</strong> 0 als er e<strong>en</strong> 1 op die plaats staat. Dat nieuwe getal is<br />

100


1 000100100100100010010......<br />

2 010101001010010010001......<br />

3 100101111010111100001......<br />

4 111010010111000101011......<br />

5 010101101110101001011......<br />

6 010010010010101010011......<br />

...<br />

diag: 101110.....<br />

Figuur 6.2: Cantor’s diagonaal<br />

óók e<strong>en</strong> getal tuss<strong>en</strong> 0 <strong>en</strong> 1, maar staat nerg<strong>en</strong>s in die rij. Dus kan zo’n opsomming niet gemaakt word<strong>en</strong>.<br />

Ons bewijs dat er e<strong>en</strong> taal in EXP is die niet in polynomiale tijd herk<strong>en</strong>d kan word<strong>en</strong> loopt ook over de<br />

diagonaal <strong>van</strong> Turingmachine/polynoom <strong>en</strong> invoer par<strong>en</strong>. We stell<strong>en</strong> ons voor dat we e<strong>en</strong> figuur met e<strong>en</strong><br />

x <strong>en</strong> e<strong>en</strong> y as hebb<strong>en</strong> waarlangs de natuurlijke getall<strong>en</strong> staan. Langs de x as interpreter<strong>en</strong> we de getall<strong>en</strong><br />

als de combinatie <strong>van</strong> natuurlijk getal/polynoom, <strong>en</strong> langs de y as interpreter<strong>en</strong> we de getall<strong>en</strong> gewoon als<br />

natuurlijke getall<strong>en</strong>. De machine die we voorstell<strong>en</strong> krijgt e<strong>en</strong> paar x, y als invoer <strong>en</strong> voert het programma<br />

in Figuur 6.3 uit.<br />

1: input x;<br />

2: schrijf op e<strong>en</strong> aparte band 2 |x|+|y| keer e<strong>en</strong> 1.<br />

3: Laag het aantal 1 af <strong>en</strong> ver<strong>van</strong>g in de volg<strong>en</strong>de stapp<strong>en</strong> steeds e<strong>en</strong> 1 door e<strong>en</strong> B. Als deze band tuss<strong>en</strong>tijds<br />

leeg raakt, stop <strong>en</strong> verwerp.<br />

4: decodeer x in P <strong>en</strong> q waar P e<strong>en</strong> Turing machine programma is <strong>en</strong> q e<strong>en</strong> polynoom;<br />

5: simuleer {P } op x voor q(|x|) stapp<strong>en</strong>.<br />

6: if {P } heeft nog niet geaccepteerd th<strong>en</strong> accepteer<br />

7: <strong>en</strong>d if<br />

8: Verwerp;<br />

Figuur 6.3: E<strong>en</strong> taal in EXP − P<br />

We bewer<strong>en</strong> <strong>en</strong>erzijds dat dit programma voor invoer l<strong>en</strong>gte n in tijd O(2 n ) loopt <strong>en</strong> anderzijds dat er ge<strong>en</strong><br />

<strong>en</strong>kel programma M, <strong>en</strong> polynoom p bestaat, zo dat M precies de invoer<strong>en</strong> accepteert die dit programma<br />

accepteert in tijd begr<strong>en</strong>sd door p. De eerste bewering is evid<strong>en</strong>t, aangezi<strong>en</strong> we e<strong>en</strong> geklokte Turing machine<br />

gebruik<strong>en</strong> die na ongeveer 2 n stapp<strong>en</strong> stopt. Deze Turing machine moet daarvoor eerst wel 2 n berek<strong>en</strong><strong>en</strong>,<br />

maar dat kan gemakkelijk in 2 n stapp<strong>en</strong> (hoe?). We nem<strong>en</strong> nog iets meer afstand <strong>en</strong> nem<strong>en</strong> aan dat q e<strong>en</strong><br />

polynoom is zo dat elke n stapp<strong>en</strong> <strong>van</strong> M op invoer <strong>van</strong> l<strong>en</strong>gte n in q(n) stapp<strong>en</strong> gesimuleerd kunn<strong>en</strong> word<strong>en</strong>.<br />

Stel nu dat er e<strong>en</strong> machine M is <strong>en</strong> e<strong>en</strong> polynoom p, zo dat M de bov<strong>en</strong>beschrev<strong>en</strong> taal herk<strong>en</strong>t in hoogst<strong>en</strong>s<br />

p(n) stapp<strong>en</strong>. Deze machine M heeft e<strong>en</strong> programma dat als binaire string gecodeerd kan word<strong>en</strong>. Weg<strong>en</strong>s<br />

het padding lemma is er e<strong>en</strong> codering P voor dit programma, zo dat q(p(n)) (veel) kleiner is dan 2 n . Dus<br />

als we het programma P op invoer <strong>van</strong> l<strong>en</strong>gte n simuler<strong>en</strong>, dan stopt het programma altijd. Lat<strong>en</strong> we e<strong>en</strong>s<br />

zi<strong>en</strong> wat M met e<strong>en</strong> getal als invoer dat het paar P, p codeert. Het voert P uit op invoer P, p voor p(|P, p|)<br />

gesimuleerde stapp<strong>en</strong>, wat dus minder dan q(p(|P, p|)) < 2 |P,p| werkelijke stapp<strong>en</strong> kost. Maar dan accepteert<br />

zij de invoer P, p dan <strong>en</strong> slechts dan als P de invoer P, p verwerpt. Onze aanname dat P, p (altijd) door p(n)<br />

begr<strong>en</strong>sd is moet dus fout zijn.<br />

6.1.4 somm<strong>en</strong><br />

1. E<strong>en</strong> functie f heet tijdconstrueerbaar als er e<strong>en</strong> Turingmachine bestaat <strong>en</strong> voor elke n e<strong>en</strong> invoer<br />

<strong>van</strong> l<strong>en</strong>gte n waarop M precies f(n) toestandsovergang<strong>en</strong> doormaakt <strong>en</strong> dan stopt. Laat zi<strong>en</strong> dat de<br />

volg<strong>en</strong>de functies tijdconstrueerbaar zijn. Laat zi<strong>en</strong> dat n, n 2 , 2 n <strong>en</strong> n! tijdconstrueerbaar zijn. Zijn<br />

er ook functies die niet tijdconstrueerbaar zijn?<br />

101


2. Toon aan dat het programma uit Figuur 6.3 zo kan word<strong>en</strong> aangepast dat ermee bewez<strong>en</strong> wordt dat<br />

er e<strong>en</strong> taal bestaat die wel in tijd O(n log n herk<strong>en</strong>d kan word<strong>en</strong> maar niet in polynomiale tijd.<br />

3. Pas het programma zo aan dat ermee bewez<strong>en</strong> wordt dat er e<strong>en</strong> taal is die in geheug<strong>en</strong> n 2 herk<strong>en</strong>d kan<br />

word<strong>en</strong> die niet in geheug<strong>en</strong> O(log n) herk<strong>en</strong>d kan word<strong>en</strong>.<br />

6.2 NP Problem<strong>en</strong><br />

Expon<strong>en</strong>tiële tijd begr<strong>en</strong>sde algoritm<strong>en</strong> zijn alle<strong>en</strong> interessant voor zeer kleine instanties. Meestal komt het<br />

uitvoer<strong>en</strong> <strong>van</strong> e<strong>en</strong> expon<strong>en</strong>tiële tijd begr<strong>en</strong>sde algoritme neer op het bekijk<strong>en</strong> <strong>van</strong> alle mogelijke oplossing<strong>en</strong><br />

<strong>van</strong> e<strong>en</strong> probleem <strong>en</strong> daaruit de goede of meest geschikte oplossing te selecter<strong>en</strong>. Wij k<strong>en</strong>n<strong>en</strong> deze procedure<br />

ook wel onder de naam ” exhaustive search” of, in het Russisch, ” perebor”. Het bewijz<strong>en</strong> dat e<strong>en</strong> probleem<br />

alle<strong>en</strong> kan word<strong>en</strong> opgelost door het toepass<strong>en</strong> <strong>van</strong> exhaustive search wordt in het algeme<strong>en</strong> geaccepteerd<br />

als e<strong>en</strong> bewijs dat het probleem ondo<strong>en</strong>lijk is <strong>en</strong> dat alle<strong>en</strong> zeer kleine instanties <strong>van</strong> het probleem kunn<strong>en</strong><br />

word<strong>en</strong> opgelost. Ook wordt zo’n bewijs geaccepteerd als e<strong>en</strong> excuus om te zoek<strong>en</strong> naar algoritm<strong>en</strong> die<br />

niet in alle gevall<strong>en</strong> e<strong>en</strong> oplossing voor het probleem gev<strong>en</strong> <strong>en</strong>/of slechts e<strong>en</strong> b<strong>en</strong>adering <strong>van</strong> de optimale<br />

oplossing. De problem<strong>en</strong> die bewijsbaar niet kunn<strong>en</strong> word<strong>en</strong> opgelost vall<strong>en</strong> buit<strong>en</strong> het bereik <strong>van</strong> deze tekst.<br />

Problem<strong>en</strong> waarvoor zo’n bewijs niet bestaat, maar wel e<strong>en</strong> efficiënte b<strong>en</strong>aderingsalgoritme kom<strong>en</strong> verderop<br />

in deze tekst nog wel aan de orde.<br />

We kom<strong>en</strong> eerst toe aan de id<strong>en</strong>tificatie <strong>van</strong> e<strong>en</strong> klasse <strong>van</strong> problem<strong>en</strong> die er alle schijn <strong>van</strong> hebb<strong>en</strong> dat ze<br />

tot de klasse <strong>van</strong> zeer moeilijke problem<strong>en</strong> hor<strong>en</strong>, maar waarvoor tot op hed<strong>en</strong> ge<strong>en</strong> bewijs bestaat dat dat<br />

zo is. Van al deze problem<strong>en</strong> wet<strong>en</strong> we dat ze kunn<strong>en</strong> word<strong>en</strong> opgelost met exhaustive search. Tot op hed<strong>en</strong><br />

wet<strong>en</strong> we echter niet of ze alle<strong>en</strong> maar met exhaustive search kunn<strong>en</strong> word<strong>en</strong> opgelost. Deze problem<strong>en</strong><br />

zijn sterk aan elkaar verwant <strong>en</strong> de vraag of exhaustive search de <strong>en</strong>ige mogelijke oplossing is, is bov<strong>en</strong>di<strong>en</strong><br />

dring<strong>en</strong>d. Het zijn namelijk problem<strong>en</strong> die in de praktijk vaak voorkom<strong>en</strong>. Voordat we de eig<strong>en</strong>schapp<strong>en</strong><br />

<strong>van</strong> deze problem<strong>en</strong> in detail gaan ontled<strong>en</strong>, bekijk<strong>en</strong> we eerst e<strong>en</strong> aantal voorbeeld<strong>en</strong>. Hiervoor gebruik<strong>en</strong><br />

we e<strong>en</strong> vast formaat. Eerst gev<strong>en</strong> we de naam waaronder het probleem bek<strong>en</strong>d is, vervolg<strong>en</strong>s beschrijv<strong>en</strong> we<br />

de invoer <strong>van</strong> het probleem zoals deze aan de Turing machine wordt voorgesteld <strong>en</strong> t<strong>en</strong>slotte stell<strong>en</strong> we de<br />

vraag die door de Turing machine moet word<strong>en</strong> beantwoord. Dit antwoord is altijd <strong>van</strong> de ja/nee vorm. De<br />

Turing machine moet accepter<strong>en</strong> of verwerp<strong>en</strong>. We gev<strong>en</strong> eerst e<strong>en</strong> voorbeeld <strong>van</strong> hoe zo’n probleem gesteld<br />

wordt.<br />

naam: KRAL<br />

gegev<strong>en</strong>: Het Tora Bora gebergte bevat e<strong>en</strong> groot aantal grott<strong>en</strong> <strong>en</strong> n vlieg<strong>en</strong>de drak<strong>en</strong>. Van elke draak<br />

is e<strong>en</strong> deelverzameling grott<strong>en</strong> bek<strong>en</strong>d waarin hij zich kan bevind<strong>en</strong>. Als e<strong>en</strong> draak zich in de grot<br />

bevindt wanneer e<strong>en</strong> ridder binn<strong>en</strong>komt, is de ruimte te krap om goed te beweg<strong>en</strong> <strong>en</strong> is de draak<br />

kansloos. Als de ridder zich in de grot bevindt wanneer de draak binn<strong>en</strong>komt, vult de draak de grot<br />

met vuur <strong>en</strong> is de ridder kansloos. In het boek KRAL staan voor ieder uur <strong>van</strong> de dag m drietall<strong>en</strong>.<br />

Als je <strong>van</strong> elk drietal twee getall<strong>en</strong> kunt wegstrep<strong>en</strong> zodat n verschill<strong>en</strong>de getall<strong>en</strong> overblijv<strong>en</strong>, zijn dat<br />

de grott<strong>en</strong> waarin zich op dat uur <strong>van</strong> de dag e<strong>en</strong> draak bevindt.<br />

gevraagd: Kan de koningin <strong>van</strong> het land n ridders erop uitstur<strong>en</strong> die op e<strong>en</strong> bepaald uur <strong>van</strong> de dag<br />

alle drak<strong>en</strong> tegelijkertijd verslaan?<br />

We zull<strong>en</strong> veel <strong>van</strong> deze problem<strong>en</strong> in deze tekst behandel<strong>en</strong>. De bov<strong>en</strong>gegev<strong>en</strong> repres<strong>en</strong>tatie is e<strong>en</strong><br />

makkelijke manier om de problem<strong>en</strong> te definier<strong>en</strong>. Elk probleem is altijd e<strong>en</strong> oneindige verzameling <strong>van</strong><br />

instanties (voor elk gebergte kan het aantal drak<strong>en</strong>, grott<strong>en</strong> <strong>en</strong> ridders variër<strong>en</strong>), <strong>en</strong> we zijn geinteresseerd in<br />

hoe moelijk e<strong>en</strong> ev<strong>en</strong>tuele algoritme is die voor elke instantie <strong>van</strong> het probleem gebruikt kan word<strong>en</strong> (eindige<br />

problem<strong>en</strong> zijn, <strong>van</strong>wege onze eerder aannam<strong>en</strong> over constant<strong>en</strong> natuurlijk niet interessant). We kunn<strong>en</strong><br />

lang niet alle interessante problem<strong>en</strong> <strong>van</strong> deze vorm behandel<strong>en</strong>. Dat zijn er e<strong>en</strong>voudig te veel. In ieder geval<br />

zull<strong>en</strong> wel de volg<strong>en</strong>de problem<strong>en</strong> in onze te behandel<strong>en</strong> lijst voorkom<strong>en</strong>.<br />

1. naam: Traveling Salesperson<br />

gegev<strong>en</strong>: E<strong>en</strong> volledige graaf G = (V, E) met e<strong>en</strong> gewichtsfunctie g : E ↦→ R, <strong>en</strong> e<strong>en</strong> getal K<br />

102


gevraagd: Heeft G e<strong>en</strong> Hamilton circuit waar<strong>van</strong> het totale gewicht kleiner dan K is?<br />

2. naam: Kleurbaarheid<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G = (V, E) <strong>en</strong> e<strong>en</strong> getal K<br />

gevraagd: Bestaat er e<strong>en</strong> functie c : V ↦→ K, zo dat voor ge<strong>en</strong> paar (v, w) ∈ E geldt c(v) = c(w)?<br />

3. naam: Boedelscheiding<br />

gegev<strong>en</strong>: E<strong>en</strong> verzameling getall<strong>en</strong> {w1, . . . , wn}<br />

gevraagd: Bestaat er e<strong>en</strong> indexverzameling I ⊆ {1, . . . , n} zodat geldt �<br />

i∈I wi = �<br />

i /∈I wi?<br />

4. naam: Exacte Overdekking<br />

gegev<strong>en</strong>: E<strong>en</strong> stel deelverzameling<strong>en</strong> S1, . . . , Sm <strong>van</strong> U = {1, . . . , n}<br />

gevraagd: Bestaat er e<strong>en</strong> indexverzameling I ⊆ {1, . . . , m} zo dat �<br />

i∈I Si = U terwijl voor alle<br />

i �= j geldt Si ∩ Sj = ∅?<br />

5. naam: Knapsack<br />

gegev<strong>en</strong>: E<strong>en</strong> verzameling getall<strong>en</strong> {w1, . . . , wn} <strong>en</strong> e<strong>en</strong> getal b<br />

gevraagd: Bestaat er e<strong>en</strong> indexverzameling I zo dat �<br />

i∈I wi = b?<br />

6. naam: Knoopoverdekking<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G = (V, E) <strong>en</strong> e<strong>en</strong> getal K<br />

gevraagd: Is er e<strong>en</strong> deelverzameling V ′ ⊆ V met |V ′ | ≤ K zo dat voor elk paar (v, w) ∈ E geldt<br />

{v, w} ∩ V ′ �= ∅?<br />

7. naam: Vervulbaarheid<br />

gegev<strong>en</strong>: E<strong>en</strong> propositie <strong>van</strong> n boolese variabel<strong>en</strong> F (x1, . . . , xn)<br />

gevraagd: Is er e<strong>en</strong> toewijzing <strong>van</strong> waarheidswaard<strong>en</strong> aan {x1, . . . , xn} die F waar maakt?<br />

8. naam: Hamilton Circuit<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G<br />

gevraagd: Heeft G e<strong>en</strong> <strong>en</strong>kelvoudige cykel langs alle knop<strong>en</strong>?<br />

9. naam: Clique<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G = (V, E) <strong>en</strong> e<strong>en</strong> getal K<br />

gevraagd: Heeft G e<strong>en</strong> volledige ondergraaf <strong>van</strong> grootte t<strong>en</strong>minste K<br />

10. naam: Onafhankelijke Verzameling<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G = V, E <strong>en</strong> e<strong>en</strong> getal K<br />

gevraagd: Heeft G e<strong>en</strong> onafhankelijke verzameling <strong>van</strong> grootte minst<strong>en</strong>s K?<br />

11. naam: Betegeling<br />

gegev<strong>en</strong>: E<strong>en</strong> N × N vierkant met kleur<strong>en</strong> aan de rand, <strong>en</strong> e<strong>en</strong> verzameling gekleurde tegels<br />

gevraagd: Kan het vierkant met deze verzameling tegels word<strong>en</strong> volgelegd?<br />

Deze lijst kan nog eindeloos word<strong>en</strong> verl<strong>en</strong>gd met problem<strong>en</strong> <strong>van</strong> dezelfde soort. In 1979 hebb<strong>en</strong> Michael<br />

Garey <strong>en</strong> David Johnson [GJ79] de to<strong>en</strong>malige stand <strong>van</strong> zak<strong>en</strong> opgetek<strong>en</strong>d in hun boek <strong>en</strong> e<strong>en</strong> lijst <strong>van</strong> ongeveer<br />

500 <strong>van</strong> deze problem<strong>en</strong> daarin opg<strong>en</strong>om<strong>en</strong>. Sindsdi<strong>en</strong> is deze lijst op alle gebied<strong>en</strong> <strong>van</strong> de wet<strong>en</strong>schap<br />

alle<strong>en</strong> maar gegroeid.<br />

Wat is de eig<strong>en</strong>schap die deze problem<strong>en</strong> bindt? Het zijn meerdere eig<strong>en</strong>schapp<strong>en</strong>.<br />

• Allereerst kun je veel <strong>van</strong> deze problem<strong>en</strong> in de één of andere vorm in de praktijk teg<strong>en</strong>kom<strong>en</strong>.<br />

– Het kleurbaarheidsprobleem bijvoorbeeld staat voor e<strong>en</strong> hele reeks <strong>van</strong> verdelingsproblem<strong>en</strong> <strong>van</strong><br />

e<strong>en</strong> aantal zak<strong>en</strong> in e<strong>en</strong> beperkt aantal deelverzameling<strong>en</strong> die ge<strong>en</strong> punt geme<strong>en</strong> hebb<strong>en</strong>. Als<br />

bijvoorbeeld e<strong>en</strong> aantal transacties op e<strong>en</strong> computersysteem moet word<strong>en</strong> doorgevoerd waar<strong>van</strong><br />

sommige dezelfde resources gebruik<strong>en</strong> (<strong>en</strong> dus niet tegelijkertijd gestart kunn<strong>en</strong> word<strong>en</strong>) is de<br />

vraag met hoeveel kleur<strong>en</strong> zo’n verzameling gekleurd kan word<strong>en</strong> precies de vraag in hoeveel<br />

batches deze verzameling transacties kan word<strong>en</strong> uitgevoerd.<br />

103


– De vraag naar e<strong>en</strong> exacte overdekking komt voor in het vliegverkeer, waar e<strong>en</strong> vliegtuig behalve<br />

passagiers ook vliegpersoneel kan vervoer<strong>en</strong> naar e<strong>en</strong> ander vliegveld waar e<strong>en</strong> vliegtuig op ze<br />

staat te wacht<strong>en</strong>. E<strong>en</strong> overdekking met minimale overlap is er dan één waarin zo weinig mogelijk<br />

crews (<strong>en</strong> dus zoveel mogelijk betal<strong>en</strong>de passagiers) word<strong>en</strong> vervoerd.<br />

– E<strong>en</strong> knoopoverdekking zoek je als je e<strong>en</strong> verteg<strong>en</strong>woordig<strong>en</strong>de verzameling wilt vind<strong>en</strong> die voor<br />

iedere<strong>en</strong> in de geme<strong>en</strong>schap het woord kan voer<strong>en</strong> <strong>en</strong> e<strong>en</strong> onafhankelijke verzameling als je e<strong>en</strong><br />

deelverzameling <strong>van</strong> zoekt waarin niemand met iemand anders in de verzamling ruzie heeft (handig<br />

voor e<strong>en</strong> feestje).<br />

• Verder hebb<strong>en</strong> al deze problem<strong>en</strong> geme<strong>en</strong> dat er ge<strong>en</strong> algoritm<strong>en</strong> bek<strong>en</strong>d zijn om de op te loss<strong>en</strong> anders<br />

dan de exhaustive search—probeer alle mogelijke oplossing<strong>en</strong> <strong>en</strong> kies deg<strong>en</strong>e die werkt (als er één is).<br />

Er is echter voor ge<strong>en</strong> <strong>van</strong> deze problem<strong>en</strong> e<strong>en</strong> bewijs dat dat de <strong>en</strong>ige mogelijke manier is om ze op<br />

te loss<strong>en</strong>.<br />

• T<strong>en</strong>slotte kom<strong>en</strong> we bij de definier<strong>en</strong>de eig<strong>en</strong>schap <strong>van</strong> deze problem<strong>en</strong>. Dat is de volg<strong>en</strong>de. Als e<strong>en</strong><br />

oplossing voor zo’n probleem gegev<strong>en</strong> wordt, dan is e<strong>en</strong>voudig, in polynomiale tijd, te controler<strong>en</strong> dat<br />

het e<strong>en</strong> oplossing is.<br />

– Als we bijvoorbeeld e<strong>en</strong> functie krijg<strong>en</strong> die voor elke knoop in e<strong>en</strong> graaf e<strong>en</strong> kleur geeft, kunn<strong>en</strong><br />

we gemakkelijk controler<strong>en</strong> dat deze functie aan elk tweetal knop<strong>en</strong> dat aan e<strong>en</strong> kant vastzit<br />

verschill<strong>en</strong>de kleur<strong>en</strong> toewijst.<br />

– Als we e<strong>en</strong> aantal kant<strong>en</strong> in e<strong>en</strong> gewog<strong>en</strong> graaf krijg<strong>en</strong> kunn<strong>en</strong> we gemakkelijk controler<strong>en</strong> dat deze<br />

kant<strong>en</strong> e<strong>en</strong> <strong>en</strong>kelvoudig pad langs alle knop<strong>en</strong> vorm<strong>en</strong> <strong>en</strong> dat bov<strong>en</strong>di<strong>en</strong> de som <strong>van</strong> de gewicht<strong>en</strong><br />

<strong>van</strong> deze kant<strong>en</strong> b<strong>en</strong>ed<strong>en</strong> e<strong>en</strong> bepaalde gr<strong>en</strong>s ligt.<br />

– Het meest algem<strong>en</strong>e voorbeeld <strong>van</strong> dit soort problem<strong>en</strong> is wel de wiskundige stelling. Het kan lang,<br />

soms wel 300 jaar, dur<strong>en</strong> om voor e<strong>en</strong> interessante wiskundige stelling e<strong>en</strong> bewijs te vind<strong>en</strong>. Als<br />

zo’n bewijs echter e<strong>en</strong>maal gevond<strong>en</strong> is, kan elke wiskundige met voldo<strong>en</strong>de scholing controler<strong>en</strong><br />

dat het bewijs correct is in redelijke tijd. Dat er bewijz<strong>en</strong> in de literatuur zijn die incorrect zijn<br />

hoewel ze uitvoerig gecontroleerd zijn, ligt aan de vaak informele stijl <strong>van</strong> bewijsvoering. Als e<strong>en</strong><br />

bewijs in stricte logische formules gegev<strong>en</strong> wordt, dan is het controler<strong>en</strong> <strong>van</strong> zo’n bewijs alle<strong>en</strong> het<br />

mechanisch nagaan <strong>van</strong> de <strong>en</strong>e regel na de andere dat bewijsregels correct zijn toegepast. Zo’n<br />

controle zou door e<strong>en</strong> (Turing) machine gedaan kunn<strong>en</strong> word<strong>en</strong>.<br />

Om de probleemstelling te formaliser<strong>en</strong> hebb<strong>en</strong> we e<strong>en</strong> speciale variant <strong>van</strong> de Turingmachine—de nondeterministische<br />

Turing machine—nodig. We kwam<strong>en</strong> deze variant al eerder teg<strong>en</strong> in Hoofdstuk 6.1. We<br />

zull<strong>en</strong> dit model nu wat aandachtiger beschouw<strong>en</strong>.<br />

6.3 Het Nondeterministische Model<br />

Er is e<strong>en</strong> aantal manier<strong>en</strong> om het nondeterministische model <strong>van</strong> de berek<strong>en</strong>ing in te voer<strong>en</strong>. De e<strong>en</strong>voudigste<br />

vorm is die waarbij we e<strong>en</strong> deterministische variant <strong>van</strong> de Turing machine e<strong>en</strong> <strong>van</strong>tevor<strong>en</strong> op de band gegev<strong>en</strong><br />

paar, probleem-oplossing lat<strong>en</strong> controler<strong>en</strong>. Hierbij voer<strong>en</strong> we de beperking dan wel in dat de l<strong>en</strong>gte <strong>van</strong><br />

de oplossing polynomiaal is in de l<strong>en</strong>gte <strong>van</strong> het probleem, zodat ook de l<strong>en</strong>gte <strong>van</strong> de Turing machine<br />

berek<strong>en</strong>ing polynomiaal is in de l<strong>en</strong>gte <strong>van</strong> het probleem.<br />

De meest gebruikelijke karakterisering <strong>van</strong> nondeterminisme is het Turing machinemodel, waarbij de<br />

toestandsovergangsfunctie wordt veranderd in e<strong>en</strong> relatie. In plaats <strong>van</strong> één mogelijke opvolger <strong>van</strong> het paar<br />

q, a is er nu e<strong>en</strong> aantal mogelijke opvolgers, <strong>en</strong> de Turing machine mag in elke stap e<strong>en</strong> keuze mak<strong>en</strong> tuss<strong>en</strong><br />

de mogelijke opvolgers. Zo e<strong>en</strong> serie <strong>van</strong> keuzes eindigt dan na polynomiaal veel stapp<strong>en</strong> in e<strong>en</strong> accepter<strong>en</strong>de<br />

of verwerp<strong>en</strong>de toestand, <strong>en</strong> elk <strong>van</strong> de rij<strong>en</strong> <strong>van</strong> keuz<strong>en</strong> is nu e<strong>en</strong> mogelijke berek<strong>en</strong>ing op de invoer. We<br />

sprek<strong>en</strong> af dat de Turingmachine accepteert, als er e<strong>en</strong> rij keuz<strong>en</strong> bestaat die eindigt in e<strong>en</strong> accepter<strong>en</strong>de<br />

toestand.<br />

104


E<strong>en</strong> derde manier om nondeterminisme te karakterizer<strong>en</strong> is met e<strong>en</strong> exist<strong>en</strong>tiele quantor over e<strong>en</strong> verzameling<br />

<strong>van</strong> strings in l<strong>en</strong>gte begr<strong>en</strong>sd door e<strong>en</strong> polynoom in de l<strong>en</strong>gte <strong>van</strong> de probleemstelling. We<br />

veronderstell<strong>en</strong> dat er e<strong>en</strong> (deterministisch) polynomiale tijd berek<strong>en</strong>baar predicaat R bestaat dat op invoer<br />

x, y het antwoord 0 of 1 kan gev<strong>en</strong> <strong>en</strong> krijg<strong>en</strong> e<strong>en</strong> karakterizering <strong>van</strong> nondeterminisme in de expressie<br />

(∃y)[|y| ≤ p(|x|) ∧ R(x, y)].<br />

Al deze manier<strong>en</strong> om nondeterminisme te beschrijv<strong>en</strong> zijn equival<strong>en</strong>t, <strong>en</strong> het is aan de lezer om e<strong>en</strong> keuze<br />

te mak<strong>en</strong> die het best bij de intuïtie past. In deze tekst zull<strong>en</strong> we voor het nondeterministische Turing<br />

machinemodel kiez<strong>en</strong>, voornamelijk om historische red<strong>en</strong><strong>en</strong>.<br />

Het is niet nodig de l<strong>en</strong>gte <strong>van</strong> de oplossing begr<strong>en</strong>sd te houd<strong>en</strong> tot polynomiale afmeting<strong>en</strong>. Als we<br />

de l<strong>en</strong>gte <strong>van</strong> de oplossing expon<strong>en</strong>tieel lat<strong>en</strong> groei<strong>en</strong>, krijg<strong>en</strong> we de nondeterministische variant <strong>van</strong> expon<strong>en</strong>tiële<br />

tijd (NEXP), maar ook grotere l<strong>en</strong>gtes gev<strong>en</strong> karakterizering <strong>van</strong> nondeterministische klass<strong>en</strong><br />

(dubbel, drievoudig, tot <strong>en</strong> met n-voudig nondeterministisch expon<strong>en</strong>tiële tijd). De eerste klasse waarbij<br />

nondeterminisme <strong>en</strong> determinisme gelijk zijn is de klasse ELEMENTARY, waar e<strong>en</strong> rek<strong>en</strong>tijd wordt toegestaan<br />

die e<strong>en</strong> herhaalde macht <strong>van</strong> twee is (222... ) <strong>en</strong> waarbij het aantal herhaling<strong>en</strong> lineair is. Uiteraard<br />

kunn<strong>en</strong> nondeterministische berek<strong>en</strong>ing<strong>en</strong> gesimuleerd word<strong>en</strong> op e<strong>en</strong> deterministische machine die expon<strong>en</strong>tieel<br />

veel meer rek<strong>en</strong>tijd heeft. Immers, deze machine kan alle mogelijke nondeterministische keuz<strong>en</strong> één voor<br />

één prober<strong>en</strong> om te zi<strong>en</strong> of misschi<strong>en</strong> één <strong>van</strong> deze keuz<strong>en</strong> eindigt in e<strong>en</strong> accepter<strong>en</strong>de toestand. Als we dus de<br />

klasse <strong>van</strong> problem<strong>en</strong> waarvoor e<strong>en</strong> nondeterministische polynomiale tijd begr<strong>en</strong>sde Turing machine bestaat<br />

aanduid<strong>en</strong> met NP, dan krijg<strong>en</strong> we voor de tot nu toe bekek<strong>en</strong> klass<strong>en</strong> de inclusierelatie P ⊆ NP ⊆ EXP.<br />

Aangezi<strong>en</strong> we hebb<strong>en</strong> aangetoond dat P �= EXP moet één <strong>van</strong> beide inclusies echt zijn, het is echter tot op<br />

hed<strong>en</strong> onbek<strong>en</strong>d welke.<br />

6.4 Reductie<br />

Stel dat we in de winkel e<strong>en</strong> programma kop<strong>en</strong> voor het oploss<strong>en</strong> <strong>van</strong> lineaire vergelijking<strong>en</strong>. Het programma<br />

is e<strong>en</strong> implem<strong>en</strong>tatie <strong>van</strong> de snelst bek<strong>en</strong>de algoritme <strong>en</strong> het lost problem<strong>en</strong> <strong>van</strong> de vorm Ax = b op, waarbij<br />

A e<strong>en</strong> matrix is, b e<strong>en</strong> vector <strong>en</strong> x het rijtje onbek<strong>en</strong>d<strong>en</strong>. Thuisgekom<strong>en</strong> will<strong>en</strong> we natuurlijk graag dit<br />

programma inzett<strong>en</strong> om het ons al tijd<strong>en</strong> erger<strong>en</strong>de probleem op te loss<strong>en</strong>, maar het werkt niet. Als we de<br />

kleine lettertjes in de gebruiksaanwijzing lez<strong>en</strong>, kom<strong>en</strong> we erachter dat het programma alle<strong>en</strong> werkt voor<br />

symmetrische matrices, <strong>en</strong> er is ook ge<strong>en</strong> garantie. Niet goed, geld kwijt. Het probleem is echter veel minder<br />

groot dan het lijkt. Immers in onze kast hebb<strong>en</strong> we nog e<strong>en</strong> algoritme voor matrixverm<strong>en</strong>igvuldiging, dat<br />

ook werkt voor matrix-vector verm<strong>en</strong>igvuldiging <strong>en</strong> we herinner<strong>en</strong> ons nog <strong>van</strong> de less<strong>en</strong> lineaire algebra,<br />

dat we e<strong>en</strong> matrix A symmetrisch kunn<strong>en</strong> mak<strong>en</strong> door hem te verm<strong>en</strong>igvuldig<strong>en</strong> met zijn getransponeerde<br />

A T . In plaats <strong>van</strong> Ax = b op te loss<strong>en</strong>, loss<strong>en</strong> we nu het probleem A T Ax = A T b op <strong>en</strong> vind<strong>en</strong> de gezochte<br />

oplossing.<br />

We hebb<strong>en</strong> het probleem <strong>van</strong> het oploss<strong>en</strong> <strong>van</strong> e<strong>en</strong> stelsel <strong>van</strong> lineaire vergelijking<strong>en</strong> vertaald in het<br />

probleem <strong>van</strong> het oploss<strong>en</strong> <strong>van</strong> e<strong>en</strong> stelsel lineaire vergelijking<strong>en</strong> waar<strong>van</strong> de coëffici<strong>en</strong>t<strong>en</strong>matrix symmetrisch<br />

is. Behalve dat dit betek<strong>en</strong>t dat we onze felbegeerde oplossing in hand<strong>en</strong> krijg<strong>en</strong>, zegt dit ook iets over het<br />

probleem <strong>van</strong> het oploss<strong>en</strong> <strong>van</strong> e<strong>en</strong> stelsel lineaire vergelijking<strong>en</strong>. We hebb<strong>en</strong> te mak<strong>en</strong> met twee problem<strong>en</strong>.<br />

Het algem<strong>en</strong>e probleem <strong>van</strong> het oploss<strong>en</strong> <strong>van</strong> e<strong>en</strong> stelsel lineaire vergelijking<strong>en</strong> <strong>en</strong> het specifieke probleem<br />

<strong>van</strong> het oploss<strong>en</strong> <strong>van</strong> e<strong>en</strong> stelsel lineaire vergelijking<strong>en</strong> met e<strong>en</strong> symmetrische coëffici<strong>en</strong>t<strong>en</strong>matrix. Meestal<br />

kunn<strong>en</strong> we alle<strong>en</strong> maar zegg<strong>en</strong> dat het algem<strong>en</strong>e probleem minst<strong>en</strong>s zo moelijk moet zijn als het specifieke<br />

probleem. Immers e<strong>en</strong> algoritme die e<strong>en</strong> oplossing geeft voor het algem<strong>en</strong>e probleem geeft ook e<strong>en</strong> oplossing<br />

voor het specifieke probleem. Omdat we nu echter beschikk<strong>en</strong> over e<strong>en</strong> vertaling <strong>van</strong> het algem<strong>en</strong>e probleem<br />

naar het specifieke probleem, kunn<strong>en</strong> we ook zegg<strong>en</strong> dat het algem<strong>en</strong>e probleem niet moeilijker is dan het<br />

specifieke probleem. Immers gegev<strong>en</strong> e<strong>en</strong> instantie <strong>van</strong> het algem<strong>en</strong>e probleem, <strong>en</strong> e<strong>en</strong> algoritme voor het<br />

specifieke probleem, kunn<strong>en</strong> we de vertaling <strong>en</strong> deze algoritme schakel<strong>en</strong> om zo e<strong>en</strong> oplossing voor deze<br />

instantie te krijg<strong>en</strong>. De vertaling die we hebb<strong>en</strong> gevond<strong>en</strong>, reduceert onze zoektocht naar e<strong>en</strong> oplossing voor<br />

het algem<strong>en</strong>e probleem naar het zoek<strong>en</strong> naar e<strong>en</strong> oplossing voor het specifieke probleem. De reductie moet<br />

wel aan e<strong>en</strong> paar voorwaard<strong>en</strong> voldo<strong>en</strong>. Stel we hebb<strong>en</strong> e<strong>en</strong> reductie <strong>van</strong> probleem A, het bronprobleem, naar<br />

probleem B, het doelprobleem. Deze reductie geeft voor elke x e<strong>en</strong> vertaling f(x) zo dat uit e<strong>en</strong> oplossing<br />

105


voor f(x) gemakkelijk e<strong>en</strong> oplossing voor x kan word<strong>en</strong> afgeleid.<br />

1. De reductie zelf mag niet al te ingewikkeld zijn. In het bijzonder mag de reductie nooit gebruik mak<strong>en</strong><br />

<strong>van</strong> eig<strong>en</strong>schapp<strong>en</strong> <strong>van</strong> de oplossing voor probleem A, omdat je om die te in hand<strong>en</strong> te krijg<strong>en</strong> eerst<br />

die oplossing zou moet<strong>en</strong> berek<strong>en</strong><strong>en</strong>.<br />

2. Het resultaat <strong>van</strong> de reductie, de vertaling, mag niet veel langer zijn dan het originele probleem. Anders<br />

is de sam<strong>en</strong>stelling <strong>van</strong> de vertaling <strong>en</strong> de efficiënte algoritme voor het probleem waarnaartoe wordt<br />

gereduceerd ge<strong>en</strong> efficiënte algoritme voor het originele probleem meer, zoals we hadd<strong>en</strong> bedoeld. De<br />

efficiënte algoritme is immers efficiënt in de l<strong>en</strong>gte <strong>van</strong> de vertaling.<br />

Aan deze voorwaard<strong>en</strong> wordt voldaan door te eis<strong>en</strong> dat de vertaling/reductie polynomiale tijd begr<strong>en</strong>sd<br />

is. Immers in polynomiale tijd kan de reductie niet meer dan polynomiaal veel uitvoer g<strong>en</strong>erer<strong>en</strong>. Als<br />

zowel de vertaling/reductie polynomiale tijd begr<strong>en</strong>sd is als de algoritme voor het doelprobleem, dan is de<br />

sam<strong>en</strong>stelling <strong>van</strong> de vertaling <strong>en</strong> deze algoritme e<strong>en</strong> polynomiale tijd algoritme voor het bronprobleem.<br />

6.5 NP-volledigheid<br />

Het nondeterministische Turing machinemodel is (in polynomiale tijd begr<strong>en</strong>sd) het definiër<strong>en</strong>de model voor<br />

de complexiteitsklasse NP. Problem<strong>en</strong> in deze klasse word<strong>en</strong> gedefiniëerd door e<strong>en</strong> Turing machine <strong>en</strong> e<strong>en</strong><br />

polynoom. Het polynoom, uitgerek<strong>en</strong>d in de l<strong>en</strong>gte <strong>van</strong> de invoer geeft e<strong>en</strong> tijdgr<strong>en</strong>s (is gr<strong>en</strong>s op het aantal<br />

stapp<strong>en</strong>). Als er e<strong>en</strong> berek<strong>en</strong>ing <strong>van</strong> de (nondeterministische) Turing machine bestaat die eindigt met “ja”<br />

<strong>en</strong> die korter is dan de tijdgr<strong>en</strong>s, dan zegg<strong>en</strong> we dat de Turing machine de invoer accepteert, of ook wel<br />

dat de invoer e<strong>en</strong> instantie <strong>van</strong> het probleem is, of ook wel elem<strong>en</strong>t <strong>van</strong> de verzameling die het probleem<br />

beschrijft. Dit betek<strong>en</strong>t dat het aantal problem<strong>en</strong> in NP (net zoals overig<strong>en</strong>s in alle andere door ons bekek<strong>en</strong><br />

complexiteitsklass<strong>en</strong> ) aftelbaar is. Ieder paar Turing machine-polynoom definieert e<strong>en</strong> probleem in NP <strong>en</strong><br />

omgekeerd bestaat er voor elk probleem in NP zo’n paar.<br />

We wet<strong>en</strong> niet of NP problem<strong>en</strong> herbergt die expon<strong>en</strong>tiële rek<strong>en</strong>tijd verg<strong>en</strong>. Elk lang g<strong>en</strong>oeg tijdsinterval<br />

(d<strong>en</strong>k aan e<strong>en</strong> jaar) ziet wel e<strong>en</strong> voorstel voor zo’n probleem, maar het bewijs is meestal <strong>van</strong> de vorm ” ...<strong>en</strong><br />

daarom is er ge<strong>en</strong> andere mogelijkheid e<strong>en</strong> oplossing te vind<strong>en</strong> dan alle mogelijke oplossing<strong>en</strong> te prober<strong>en</strong>.”<br />

Zulke bewijz<strong>en</strong> zijn—tot nu toe—allemaal fout geblek<strong>en</strong>. Er is echter e<strong>en</strong> deelklasse <strong>van</strong> problem<strong>en</strong> in NP<br />

waar<strong>van</strong> het niet duidelijk is, <strong>en</strong> zo langzamerhand <strong>van</strong>wege alle poging<strong>en</strong> onwaarschijnlijk wordt, dat ze<br />

deterministisch polynomiale tijd begr<strong>en</strong>sde algoritm<strong>en</strong> hebb<strong>en</strong>. Deze deelklasse heeft bov<strong>en</strong>di<strong>en</strong> de eig<strong>en</strong>schap<br />

dat alle problem<strong>en</strong> die erin zitt<strong>en</strong> allemaal wel, of juist allemaal niet e<strong>en</strong> deterministische polynomiale tijd<br />

begr<strong>en</strong>sde algoritme hebb<strong>en</strong>. In het bijzonder geldt voor deze klasse dat als voor één <strong>van</strong> deze problem<strong>en</strong> e<strong>en</strong><br />

polynomiale tijd algoritme zou bestaan, dan bestaat er e<strong>en</strong> polynomiale tijd algoritme voor alle problem<strong>en</strong><br />

in NP. We noem<strong>en</strong> deze problem<strong>en</strong> NP-volledig, omdat ze de volledige complexiteit <strong>van</strong> de klasse NP in zich<br />

drag<strong>en</strong>.<br />

Hoe zoud<strong>en</strong> we <strong>van</strong> e<strong>en</strong> probleem in NP bewijz<strong>en</strong> dat het deze eig<strong>en</strong>schap heeft? Hiertoe gebruik<strong>en</strong> we<br />

het hierbov<strong>en</strong> geïntroduceerde middel <strong>van</strong> de reductie. Als we e<strong>en</strong> polynomiale tijd berek<strong>en</strong>bare functie f<br />

hebb<strong>en</strong>, zo dat voor elke x <strong>en</strong> twee deelverzameling<strong>en</strong> A <strong>en</strong> B <strong>van</strong> {0, 1} ∗ geldt x ∈ A dan <strong>en</strong> slechts dan<br />

als f(x) ∈ B, dan is elke algoritme die y ∈ B kan besliss<strong>en</strong> e<strong>en</strong> algoritme die x ∈ A kan besliss<strong>en</strong> door<br />

y = f(x) te kiez<strong>en</strong>. Als voor e<strong>en</strong> probleem A in NP geldt dat er zo’n reductie f naar B bestaat, dan geldt<br />

B ∈ P ⇒ A ∈ P. Om aan te ton<strong>en</strong> dat e<strong>en</strong> probleem B dus lid is <strong>van</strong> onze klasse <strong>van</strong> NP-volledige problem<strong>en</strong><br />

hoev<strong>en</strong> we dus alle<strong>en</strong> maar aan te ton<strong>en</strong> dat er zo’n reductie fA bestaat voor elke A in NP. Er zijn echter,<br />

zoals bov<strong>en</strong> opgemerkt, aftelbaar oneindig veel problem<strong>en</strong> in NP, zodat we dit bewijs liever niet per stuk<br />

lever<strong>en</strong>. We beschrijv<strong>en</strong> e<strong>en</strong> schema voor de reductie, liever dan de reductie zelf, waarin elk afzonderlijk<br />

probleem in NP kan word<strong>en</strong> ingevuld om e<strong>en</strong> reductie <strong>van</strong> dat probleem naar ons probleem te krijg<strong>en</strong>. Om<br />

zo’n schema te krijg<strong>en</strong> mak<strong>en</strong> we gebruik <strong>van</strong> de eig<strong>en</strong>schap dat er e<strong>en</strong> nondeterministische polynomiaal<br />

begr<strong>en</strong>sde Turing machine voor probleem A bestaat als A e<strong>en</strong> probleem in NP is.<br />

Neem dus aan dat er zo’n Turing machine MA bestaat <strong>en</strong> polynoom p, zodat voor elke x geldt x ∈ A<br />

dan <strong>en</strong> slechts dan als er e<strong>en</strong> berek<strong>en</strong>ing <strong>van</strong> MA op invoer x bestaat <strong>van</strong> niet meer dan p(|x|) stapp<strong>en</strong> die<br />

106


Q0<br />

Qi<br />

Qj<br />

QF<br />

x0 x1 . . . . . . . . . xn−1 xn<br />

s t<br />

•<br />

s ′ t<br />

•<br />

Figuur 6.4: Plaatje <strong>van</strong> de Turingmachineberek<strong>en</strong>ing met instructie δ(qi, s) = 〈s ′ , qj, R〉<br />

eindigt in e<strong>en</strong> accepter<strong>en</strong>de berek<strong>en</strong>ing. We transformer<strong>en</strong> het drietal: programma <strong>van</strong> MA dat e<strong>en</strong> binair<br />

getal is, e<strong>en</strong> beschrijving <strong>van</strong> het polynoom p, dat e<strong>en</strong> ander binair getal is, <strong>en</strong> de invoer x naar e<strong>en</strong> binaire<br />

rij y zodanig dat y ∈ B dan <strong>en</strong> slechts dan als MA invoer x kan accepter<strong>en</strong> in tijd begr<strong>en</strong>sd door p(|x|). Dit<br />

is het plan. Rest nog e<strong>en</strong> geschikt probleem B te kiez<strong>en</strong>.<br />

Het probleem B wordt het eerder g<strong>en</strong>oemde probleem<br />

naam: SATISFIABILITY<br />

gegev<strong>en</strong>: E<strong>en</strong> propositie F (x1, . . . , xn)<br />

gevraagd: Is er e<strong>en</strong> toewijzing <strong>van</strong> waarheidswaard<strong>en</strong> aan x1, . . . , xn die F waar maakt<br />

.<br />

Allereerst stell<strong>en</strong> we vast dat dit zeker e<strong>en</strong> probleem in NP is. Immers e<strong>en</strong> nondeterministische Turing<br />

machine kan in n ope<strong>en</strong>volg<strong>en</strong>de keuz<strong>en</strong> e<strong>en</strong> toewijzing <strong>van</strong> waarheidswaard<strong>en</strong> bepal<strong>en</strong>, waarna in e<strong>en</strong> deterministische<br />

fase deze toewijzing gecontroleerd kan word<strong>en</strong>. Equival<strong>en</strong>t: e<strong>en</strong> gegev<strong>en</strong> oplossing kan in O(n2 )<br />

stapp<strong>en</strong> door e<strong>en</strong> deterministische Turingmachine gecontoleerd word<strong>en</strong>.<br />

Laat dus A e<strong>en</strong> probleem in NP zijn <strong>en</strong> MA e<strong>en</strong> Turing machine die voor gegev<strong>en</strong> polynoom p op invoer x<br />

e<strong>en</strong> accepter<strong>en</strong>de berek<strong>en</strong>ing MA(x) <strong>van</strong> l<strong>en</strong>gte p(|x|) heeft dan <strong>en</strong> slechts dan als x ∈ A. We merk<strong>en</strong> terzijde<br />

op dat we kunn<strong>en</strong> aannem<strong>en</strong> dat de accepter<strong>en</strong>de berek<strong>en</strong>ing MA(x) niet slechts begr<strong>en</strong>sd wordt door p(|x|),<br />

maar precies l<strong>en</strong>gte p(|x|) heeft, dit kunn<strong>en</strong> we bereik<strong>en</strong> door het programma <strong>van</strong> MA te wijzig<strong>en</strong>. Tev<strong>en</strong>s<br />

merk<strong>en</strong> wij op dat in tijd p(|x|) niet meer dan p(|x|) bandcell<strong>en</strong> kunn<strong>en</strong> word<strong>en</strong> gebruikt <strong>en</strong> dus nem<strong>en</strong> we<br />

aan dat in de berek<strong>en</strong>ing precies p(|x|) bandcell<strong>en</strong> gebruikt word<strong>en</strong>. Nu zi<strong>en</strong> we dat er e<strong>en</strong> accepter<strong>en</strong>de<br />

berek<strong>en</strong>ing <strong>van</strong> MA op invoer x bestaat precies als we het vierkant <strong>van</strong> Figuur 6.4 kunn<strong>en</strong> invull<strong>en</strong> met<br />

symbol<strong>en</strong> uit het bandalfabet S, de toestandsverzameling Q <strong>en</strong> e<strong>en</strong> merktek<strong>en</strong> dat aangeeft waar de kop is<br />

zodanig dat:<br />

1. In elke plaats in het bandvierkant precies één symbool uit het alfabet staat<br />

2. In elke rij in het toestandsvak precies één toestand staat<br />

3. In elke rij precies één cel is gemerkt als plaats <strong>van</strong> de bandkop<br />

107


4. Voor elk paar ope<strong>en</strong>volg<strong>en</strong>de rij<strong>en</strong> geldt dat op de plaats waar de bandkop niet is de symbol<strong>en</strong> in<br />

dezelfde kolom gelijk zijn<br />

5. Voor elk paar ope<strong>en</strong>volg<strong>en</strong>de rij<strong>en</strong> i, <strong>en</strong> i + 1 geldt als de bandkop op plaats i, j is dan is de bandkop op<br />

plaats i + 1, j, of op i + 1, j + 1 of op i + 1, j − 1 <strong>en</strong> deze plaats is in overe<strong>en</strong>stemming met de toestand<br />

in rij i, het symbool op plaats i, j <strong>en</strong> het programma <strong>van</strong> MA.<br />

6. Voor elk paar rij<strong>en</strong> i, i + 1 geldt dat als de bandkop op plaats i, j is, dan is het symbool op plaats<br />

i + 1, j in overe<strong>en</strong>stemming met het symbool op plaats i, j, de toestand in rij i <strong>en</strong> het programma <strong>van</strong><br />

MA.<br />

7. De eerste |x| bandsymbol<strong>en</strong> op rij 1 zijn de symbol<strong>en</strong> <strong>van</strong> x.<br />

8. De laatste toestand in rij p(|x|) is de accepter<strong>en</strong>de toestand.<br />

Als deze condities allemaal vervuld zijn, dan heeft de machine e<strong>en</strong> accepter<strong>en</strong>de berek<strong>en</strong>ing op invoer x <strong>van</strong><br />

l<strong>en</strong>gte p(|x|). We zull<strong>en</strong> nu lat<strong>en</strong> zi<strong>en</strong> dat we deze eis<strong>en</strong> kunn<strong>en</strong> vertal<strong>en</strong> in proposities die alle<strong>en</strong> waargemaakt<br />

kunn<strong>en</strong> word<strong>en</strong> als aan deze voorwaard<strong>en</strong> voldaan kan word<strong>en</strong>. De eis dat e<strong>en</strong> er e<strong>en</strong> accepter<strong>en</strong>de berek<strong>en</strong>ing<br />

<strong>van</strong> de juiste l<strong>en</strong>gte op invoer x bestaat, laat zich dan vertal<strong>en</strong> in het bestaan <strong>van</strong> e<strong>en</strong> vervulling voor de<br />

conjunctie <strong>van</strong> deze proposities. We voer<strong>en</strong> de volg<strong>en</strong>de boolese variabel<strong>en</strong> in:<br />

1. Voor elk symbool uit het bandalfabet Σ = {σ1, . . . , σm} voer<strong>en</strong> we de variabel<strong>en</strong> Sijk in met i ∈<br />

{1, . . . , m}, j, k ∈ {1, . . . , p(|x|)}. Voor elk vakje in het symbol<strong>en</strong>vierkant <strong>van</strong> Figuur 6.4 één variabele,<br />

met de betek<strong>en</strong>is dat als Sijk waargemaakt wordt om de uiteindelijke formule waar te mak<strong>en</strong>, dan is<br />

in de accepter<strong>en</strong>de berek<strong>en</strong>ing σi op plaats j, k ingevuld.<br />

2. Voor elke toestand uit de toestandsverzameling Q = {q1, . . . , qr} e<strong>en</strong> variabele Qij met i ∈ {1, . . . , r}<br />

<strong>en</strong> j ∈ {1, . . . , p(|x|)} met de betek<strong>en</strong>is dat als Qij waargemaakt wordt om de uiteindelijke formule<br />

waar te mak<strong>en</strong>, dan is in de accepter<strong>en</strong>de berek<strong>en</strong>ing qj in rij i ingevuld.<br />

3. Voor i, j ∈ {1, . . . , p(|x|)} e<strong>en</strong> variabele Tij met de betek<strong>en</strong>is dat als Tij waargemaakt wordt om de<br />

uiteindelijke formule waar te mak<strong>en</strong>, dan is in de accepter<strong>en</strong>de berek<strong>en</strong>ing in rij i het merktek<strong>en</strong> voor<br />

de kop op plaats j gezet.<br />

Om de formules overzichtelijk te houd<strong>en</strong>, voer<strong>en</strong> we e<strong>en</strong> aantal afkorting<strong>en</strong> in. Zo zal bijvoorbeeld<br />

x1 ∧ . . . ∧ xn ver<strong>van</strong>g<strong>en</strong> word<strong>en</strong> door �<br />

i xi, x1 ∨ . . . ∨ xn door �<br />

i xi <strong>en</strong> (xi ∨ xj)i�=j als afkorting word<strong>en</strong><br />

gebruikt voor de kwadratische hoeveelheid par<strong>en</strong> waarop dit past, gekoppeld door conjunctie. Ook zull<strong>en</strong> we<br />

operator<strong>en</strong> = <strong>en</strong> → gebruik<strong>en</strong> hoewel deze niet in de propositielogica voorkom<strong>en</strong>, maar uiteraard (efficiënt)<br />

in de propositielogica kunn<strong>en</strong> word<strong>en</strong> uitgedrukt. Immers xi = yj d.e.s.d.a. (xi ∧ yj) ∨ (xi ∧ yj) <strong>en</strong> xi → yj<br />

d.e.s.d.a. xi ∨ yj. Achtere<strong>en</strong>volg<strong>en</strong>s kunn<strong>en</strong> we nu de eis<strong>en</strong> voor e<strong>en</strong> accepter<strong>en</strong>de berek<strong>en</strong>ing vertal<strong>en</strong> in<br />

proposities:<br />

1. � �<br />

jk i Sijk <strong>en</strong> �<br />

jk [(Sijk ∨ Si ′ jk)i�=i ′]<br />

2. �<br />

i<br />

3. �<br />

i<br />

�<br />

j Qij <strong>en</strong> �<br />

i (Qij ∨ Qij ′)j�=j ′<br />

�<br />

j Tij <strong>en</strong> �<br />

i (Tij ∨ Tij ′)j�=j ′<br />

4. �<br />

ij Tij → [Sijk = Si+1jk]<br />

5. �<br />

ijk Qij ∧ Tik ∧ Sikℓ ⇒ [ �<br />

mj ′ k ′ Si+1km ∧ Qi+1j ′ ∧ Ti+1k ′] overe<strong>en</strong>komstig het programma <strong>van</strong> MA.<br />

6. �<br />

j≤n S0j = xj ∧ �<br />

j>n S0j = B.<br />

7. Qp(|x|) = QA.<br />

108


Als deze propositie e<strong>en</strong> vervulling heeft, dan staat in de Figuur 6.4 in elk vakje precies één symbool,<br />

<strong>van</strong>wege 1. Op elk mom<strong>en</strong>t is de machine in precies één toestand <strong>van</strong>wege 2. De bandkop is op elk mom<strong>en</strong>t<br />

op precies één plaats <strong>van</strong>wege 3. Onder elkaar staande symbol<strong>en</strong> zijn gelijk als de tapekop niet op die<br />

plaats is <strong>van</strong>wege 4. Als onder elkaar staande symbol<strong>en</strong> <strong>van</strong> elkaar verschill<strong>en</strong> dan is dat in overe<strong>en</strong>stemming<br />

met het programma <strong>van</strong>wege 5. De symbol<strong>en</strong> op de eerste rij zijn symbol<strong>en</strong> <strong>van</strong> x aangevuld met blanco<br />

symbol<strong>en</strong>, <strong>van</strong>wege 6, <strong>en</strong> de laatste toestand is de accepter<strong>en</strong>de <strong>van</strong>wege 7. Kortom, als de door deze reductie<br />

geproduceerde formule e<strong>en</strong> vervulling heeft, dan heeft het drietal programma, polynoom, invoer <strong>van</strong> waaruit<br />

hij geproduceerd is e<strong>en</strong> accepter<strong>en</strong>de berek<strong>en</strong>ing.<br />

De reductie is zeker polynomiaal begr<strong>en</strong>sd. Voor e<strong>en</strong> gegev<strong>en</strong> machine M, e<strong>en</strong> invoer x <strong>en</strong> e<strong>en</strong> polynoom<br />

p is de grootste <strong>van</strong> de zev<strong>en</strong> formules ongeveer kwadratisch (par<strong>en</strong> variabel<strong>en</strong>) in het aantal variabel<strong>en</strong>. Het<br />

aantal variabel<strong>en</strong> is zelf maximaal kwadratisch in p(|x|), hetge<strong>en</strong> in totaal e<strong>en</strong> O(p(|x|) 4 ) begr<strong>en</strong>sde reductie<br />

geeft. Voor kleine Turingmachineprogramma’s is deze gr<strong>en</strong>s toch al te groot om e<strong>en</strong> zinnig voorbeeld op te<br />

schrijv<strong>en</strong>. Het minimale aantal te gebruik<strong>en</strong> bandsymbol<strong>en</strong> is 3 (0,1,B), zodat 10 bandcell<strong>en</strong> bij 10 tijdstapp<strong>en</strong><br />

al 300 variabel<strong>en</strong> Sijk, wat dan ongeveer 900 par<strong>en</strong> in de eerste zin zou oplever<strong>en</strong>. Helaas moet<strong>en</strong> we dus<br />

hier wat betreft het toelicht<strong>en</strong> <strong>van</strong> de reductie met e<strong>en</strong> voorbeeld verstek lat<strong>en</strong> gaan.<br />

6.5.1 Meer NP-volledige problem<strong>en</strong><br />

E<strong>en</strong> reductie zoals we zojuist gezi<strong>en</strong> hebb<strong>en</strong> is e<strong>en</strong> reductieschema dat voor alle problem<strong>en</strong> in NP tegelijkertijd<br />

werkt. Zo’n reductie noem<strong>en</strong> we ook wel e<strong>en</strong> masterreductie. Vanwege de schakelbaarheid <strong>van</strong> polynom<strong>en</strong><br />

(e<strong>en</strong> polynoom <strong>van</strong> e<strong>en</strong> polynoom is opnieuw e<strong>en</strong> polynoom) hoev<strong>en</strong> we niet elke keer om de volledigheid<br />

<strong>van</strong> e<strong>en</strong> probleem te bewijz<strong>en</strong> zo’n algem<strong>en</strong>e reductie te gev<strong>en</strong>. Immers, als we e<strong>en</strong> reductie f hebb<strong>en</strong> <strong>van</strong><br />

probleem A naar probleem B <strong>en</strong> e<strong>en</strong> reductie g <strong>van</strong> probleem B naar probleem C dan geeft dit e<strong>en</strong> reductie<br />

<strong>van</strong> probleem A naar probleem C omdat we e<strong>en</strong> gegev<strong>en</strong> instantie x eerst met f vertal<strong>en</strong> naar e<strong>en</strong> instantie<br />

f(x) met de eig<strong>en</strong>schap x ∈ A ↔ f(x) ∈ B <strong>en</strong> we vervolg<strong>en</strong>s f(x) met g reducer<strong>en</strong>t tot g(f(x)) met de<br />

eig<strong>en</strong>schap dat g(f(x)) ∈ C ↔ f(x) ∈ B ↔ x ∈ A. Omdat g <strong>en</strong> f polynomiale tijd begr<strong>en</strong>sd zijn, is gf dat<br />

ook <strong>en</strong> is gf e<strong>en</strong> polynomiale tijd begr<strong>en</strong>sde reductie <strong>van</strong> A naar C.<br />

Deze observatie zull<strong>en</strong> we eerst gaan gebruik<strong>en</strong> om te lat<strong>en</strong> zi<strong>en</strong> dat e<strong>en</strong> variant <strong>van</strong> SATISFIABILITY<br />

g<strong>en</strong>aamd 3-SAT ook e<strong>en</strong> NP-volledig probleem is.<br />

naam: 3SAT<br />

gegev<strong>en</strong>: E<strong>en</strong> formule F (x1, . . . , xn) in conjunctieve normaalvorm met t<strong>en</strong> hoogste drie optred<strong>en</strong>s <strong>van</strong><br />

variabel<strong>en</strong> per zin<br />

gevraagd: Is er e<strong>en</strong> toewijzing <strong>van</strong> waarheidswaard<strong>en</strong> die F waar maakt?<br />

De reductie vertaalt e<strong>en</strong> willekeurige formule F naar e<strong>en</strong> formule F ′ in conjunctieve normaalvorm (dat<br />

is e<strong>en</strong> conjuctie <strong>van</strong> disjuncties waarin alle<strong>en</strong> variabel<strong>en</strong> of hun ontk<strong>en</strong>ning staan) met de eig<strong>en</strong>schap dat F ′<br />

waargemaakt kan word<strong>en</strong> d.e.s.d.a. F waargemaakt kan word<strong>en</strong>. De reductie gaat in twee stapp<strong>en</strong>. Eerst<br />

vertal<strong>en</strong> we e<strong>en</strong> willekeurige formule naar e<strong>en</strong> formule in conjunctieve normaalvorm <strong>en</strong> vervolg<strong>en</strong>s vertal<strong>en</strong><br />

we deze formule naar e<strong>en</strong> formule waarin precies drie optred<strong>en</strong>s <strong>van</strong> variabel<strong>en</strong> per zin staan.<br />

Gegev<strong>en</strong> e<strong>en</strong> formule F . We nem<strong>en</strong> aan dat F syntactisch correct is. Omdat de operator<strong>en</strong> ∧ <strong>en</strong> ∨ ge<strong>en</strong><br />

verschill<strong>en</strong> in prioriteit hebb<strong>en</strong> is e<strong>en</strong> formule als x1 ∧ x2 ∨ x3 niet syntactisch correct, maar e<strong>en</strong> formule als<br />

(x1 ∧x2)∨x3 is dat wel, ev<strong>en</strong>als x1 ∧(x2 ∨x3). We kunn<strong>en</strong> aannem<strong>en</strong> dat F <strong>van</strong> de vorm F = (F1)∨. . .∨(Fk)<br />

is of <strong>van</strong> de vorm F = (F1) ∧ . . . ∧ (Fk) met de eig<strong>en</strong>schap dat voor i = 1, . . . , k de formules Fi minder<br />

diep g<strong>en</strong>est zijn (dwz minder haakjespar<strong>en</strong> hebb<strong>en</strong>) dan de formule F . De reductie gaat dus met inductie<br />

naar het aantal haakjespar<strong>en</strong>, waarbij we ervoor zorg<strong>en</strong> dat, als er nog maar 1 niveau haakjes in de formule<br />

staat de formule in conjunctieve normaalvorm staat. De formule F = (F1) ∧ . . . ∧ (Fk) is al <strong>van</strong> de gew<strong>en</strong>ste<br />

vorm, zodat we ons in dat geval met de subformules kunn<strong>en</strong> gaan bezighoud<strong>en</strong>. Deze zijn echter <strong>van</strong> de<br />

form Fi = (G1) ∨ . . . ∨ (Gk) <strong>en</strong> word<strong>en</strong> dus op dezelfde manier behandeld als F wanneer deze <strong>van</strong> de vorm<br />

F = (F1) ∨ . . . ∨ (Fk) zou zijn. We behandel<strong>en</strong> dus alle<strong>en</strong> dit geval. We voer<strong>en</strong> k nieuwe variabel<strong>en</strong> y1, . . . , yk<br />

in met de eig<strong>en</strong>schap dat F alle<strong>en</strong> waargemaakt kan word<strong>en</strong> als t<strong>en</strong>minste 1 <strong>van</strong> deze variabel<strong>en</strong> waargemaakt<br />

kan word<strong>en</strong>, <strong>en</strong> bov<strong>en</strong>di<strong>en</strong> dat als yi waar is, dat dan ook Fi waar is. De nieuwe formule wordt.<br />

109


(y1 ∨ . . . yk) ∧ (y1 ∨ (F1)) . . . ∧ (yk ∨ (Fk))<br />

Het deel <strong>van</strong> de formule (y1 ∨ . . . ∨ yk) is <strong>van</strong> de juiste vorm. Alle<strong>en</strong> de stukk<strong>en</strong> yi ∨ (Fi) zijn dat nog niet.<br />

Bov<strong>en</strong>di<strong>en</strong> is het aantal haakjes in het tweede deel <strong>van</strong> de formule toeg<strong>en</strong>om<strong>en</strong>. Dat is echter schijn. We<br />

merk<strong>en</strong> op dat (Fi) <strong>van</strong> de vorm ((Gi 1)∧. . .∧(Gi ir )) is <strong>en</strong> dat elke (Gij ) <strong>van</strong> de vorm ((Hij 1 )∨. . .∨(Hij )) is. De<br />

kij<br />

formules (yi ∨(Fi)) kunn<strong>en</strong> dus geschrev<strong>en</strong> word<strong>en</strong> als (yi ∨(((Hi1 1 )∨. . .∨(H i1))∧.<br />

. .∧((Hir<br />

k1 1 )∨. . .∨(H ir<br />

kir ))).<br />

Merk op dat de zichtbare haakjesdiepte—die dus één niveau dieper is dan die <strong>van</strong> de formule F waarmee we<br />

begonn<strong>en</strong> nu vier is. Deze formule is echter equival<strong>en</strong>t met ((yi ∨ (H i1<br />

1 ) ∨ . . . ∨ (H i1<br />

ki1 )) ∧ . . . ∧ (yi ∨ (H ir<br />

1 ) ∨<br />

. . . ∨ (H ir<br />

kir<br />

))) waar<strong>van</strong> de zichtbare haakjesdiepte slechts twee is. Effectief is de diepte <strong>van</strong> de structuur dus<br />

met één haakjespaar afg<strong>en</strong>om<strong>en</strong>.<br />

De lezer met <strong>en</strong>ige achtergrond in de logica zou kunn<strong>en</strong> opmerk<strong>en</strong> dat vertaling<strong>en</strong> <strong>van</strong> conjunctieve naar<br />

disjunctieve normaalvorm<strong>en</strong> <strong>en</strong> omgekeerd ook gedaan kunn<strong>en</strong> word<strong>en</strong> met de zog<strong>en</strong>oemde wett<strong>en</strong> <strong>van</strong> de<br />

Morgan. Voor ons betoog is deze transformatie echter niet geschikt omdat ze niet effici<strong>en</strong>t is. Bekijk als<br />

voorbeeld de formule (x1 ∧ x2) ∨ (x3 ∧ x4). Pass<strong>en</strong> we de distributieve wet <strong>van</strong> de Morgan toe, dan wordt<br />

deze formule als volgt in e<strong>en</strong> equival<strong>en</strong>te conjunctie vertaald.<br />

1. (x1 ∧ x2) ∨ (x3 ∧ x4)<br />

2. (x1 ∨ (x3 ∧ x4)) ∧ (x2 ∨ (x3 ∧ x4))<br />

3. (x1 ∨ x3) ∧ (x1 ∨ x4) ∧ (x2 ∨ x3) ∧ (x2 ∨ x4).<br />

We zi<strong>en</strong> dat de formule die eerst twee haakjespar<strong>en</strong> lang was, nu vier haakjespar<strong>en</strong> lang is geword<strong>en</strong>,<br />

dus in l<strong>en</strong>gte verdubbeld. Dit f<strong>en</strong>ome<strong>en</strong> k<strong>en</strong>t deze operatie voor de distributie <strong>van</strong> elke variabele. Voor<br />

n variabel<strong>en</strong> wordt de formule dus 2 n keer zo lang. Het verschil met de bov<strong>en</strong>beschrev<strong>en</strong> methode is dat<br />

we elke nieuw ingevoerde variabele slechts één keer over alle subformules hoev<strong>en</strong> te distribuer<strong>en</strong>. Voor elke<br />

nieuwe variabele wordt de formule dus t<strong>en</strong> hoogste n sybmol<strong>en</strong> langer. Aangezi<strong>en</strong> we slechts n symbol<strong>en</strong> per<br />

stap invoer<strong>en</strong> wordt dus per stap de formule slechts n 2 symbol<strong>en</strong> langer, <strong>en</strong> aangezi<strong>en</strong> we in elke stap e<strong>en</strong><br />

haakjespaar kwijtrak<strong>en</strong> gebeurt dit hoogst<strong>en</strong>s n keer. In totaal kan de l<strong>en</strong>gte <strong>van</strong> de formule dus met O(n 3 )<br />

bits to<strong>en</strong>em<strong>en</strong> door onze transformaties.<br />

We zull<strong>en</strong> t<strong>en</strong>slotte lat<strong>en</strong> zi<strong>en</strong> dat e<strong>en</strong> formule die in conjunctieve normaalvorm staat kan word<strong>en</strong> getransformeerd<br />

naar e<strong>en</strong> equival<strong>en</strong>te formule waarin elke zin precies drie variabel<strong>en</strong> heeft. Eerst bekijk<strong>en</strong> we<br />

de zinn<strong>en</strong> <strong>van</strong> de vorm Z = (x1 ∨ . . . ∨ xn) met n > 3. Voor deze zinn<strong>en</strong> voer<strong>en</strong> we e<strong>en</strong> nieuwe variabele z in<br />

<strong>en</strong> verander<strong>en</strong> de zin in Z ′ = (x1 ∨ x2 ∨ z) ∧ (z ∨ x3 ∨ . . . ∨ xn). Als Z waargemaakt kan word<strong>en</strong>, kan 1 <strong>van</strong> de<br />

variabel<strong>en</strong> x1 of x2 waargemaakt word<strong>en</strong> of één <strong>van</strong> de variabel<strong>en</strong> x3, . . . , xn. In het eerste geval mak<strong>en</strong> we<br />

z niet waar <strong>en</strong> in het tweede geval mak<strong>en</strong> we z waar, zodat ook Z ′ waargemaakt kan word<strong>en</strong> met de zelfde<br />

toewijzing aan xi. Als Z ′ waargemaakt kan word<strong>en</strong>, dan moet z waar of niet waar gemaakt word<strong>en</strong>. In het<br />

eerste geval concluder<strong>en</strong> we dat ook één <strong>van</strong> x3, . . . , xn waargemaakt kan word<strong>en</strong> <strong>en</strong> in het tweede geval dat<br />

x1 of x2 waargemaakt kan word<strong>en</strong>. In beide gevall<strong>en</strong> kan dus ook Z waargemaakt word<strong>en</strong>.<br />

Tot slot merk<strong>en</strong> we op dat in de zin (y1 ∨y2 ∨y3)∧(y1 ∨y2 ∨y3)∧(y1 ∨y2 ∨y3)∧(y1 ∨y2 ∨y3) de variabele<br />

y3 altijd onwaar gemaakt moet word<strong>en</strong> om e<strong>en</strong> vervulling te kunn<strong>en</strong> bereik<strong>en</strong>. Twee <strong>van</strong> zulke variabel<strong>en</strong><br />

kunn<strong>en</strong> dan altijd word<strong>en</strong> gebruikt om zinn<strong>en</strong> <strong>van</strong> l<strong>en</strong>gte één of twee tot de gew<strong>en</strong>ste l<strong>en</strong>gte aan te vull<strong>en</strong>.<br />

Vertex Cover, Indep<strong>en</strong>d<strong>en</strong>t Set <strong>en</strong> Clique<br />

De drie volg<strong>en</strong>de problem<strong>en</strong> die we zull<strong>en</strong> gaan bekijk<strong>en</strong> zijn graf<strong>en</strong>problem<strong>en</strong> die bijzonder dicht bij elkaar<br />

ligg<strong>en</strong>. Dat wil zegg<strong>en</strong> dat de reductie <strong>van</strong> het <strong>en</strong>e naar het andere probleem zeer direct is <strong>en</strong> weinig ingewikkelde<br />

constructies behoeft. Allereerst hebb<strong>en</strong> we echter de uitspraak nodig dat één <strong>van</strong> deze problem<strong>en</strong><br />

NP-volledig is, <strong>en</strong> dat behoeft wel <strong>en</strong>ig werk. We kiez<strong>en</strong> voor vertex cover waarvoor we e<strong>en</strong> reductie gev<strong>en</strong><br />

<strong>van</strong> het zojuist geïd<strong>en</strong>tificeerde probleem 3SAT. Eerst de probleemstelling.<br />

naam: VERTEX COVER<br />

gegev<strong>en</strong>: E<strong>en</strong> Graaf G = (V, E) <strong>en</strong> e<strong>en</strong> getal k<br />

110


gevraagd: Bestaat er e<strong>en</strong> deelverzameling V ′ ⊆ V met de eig<strong>en</strong>schap dat |V ′ | ≤ k <strong>en</strong> voor elke e in E<br />

geldt e ∩ V ′ �= ∅?<br />

Gegev<strong>en</strong> e<strong>en</strong> formule F met variabel<strong>en</strong> x1, . . . , xn <strong>en</strong> zinn<strong>en</strong> C1, . . . , Cm waarbij elke Ci <strong>van</strong> de vorm<br />

(ℓi1 ∨ ℓi2 ∨ ℓi3 ) is met ℓij = xij of ℓij = xij . Dan mak<strong>en</strong> we e<strong>en</strong> graaf G als volgt. Voor elke variabele xi<br />

voer<strong>en</strong> we twee knop<strong>en</strong> in xi1 <strong>en</strong> xi2 die we verbind<strong>en</strong> met e<strong>en</strong> kant. Voor elke zin Cj voer<strong>en</strong> we drie knop<strong>en</strong><br />

in yj1 , yj2 <strong>en</strong> yj3 waar<strong>van</strong> we e<strong>en</strong> driehoek mak<strong>en</strong>. Als xi in Cj voorkomt op de kde plaats (k ≤ 3), dan<br />

verbind<strong>en</strong> we xi1 met yjk <strong>en</strong> als xi in Cj voorkomt op de kde plaats dan verbind<strong>en</strong> we xi2 met yjk .<br />

Stel nu dat F vervulbaar is. Dan kunn<strong>en</strong> we dus e<strong>en</strong> n-tal ℓ1, . . . , ℓn aanwijz<strong>en</strong>, zodat in elke Cj minst<strong>en</strong>s<br />

één <strong>van</strong> deze ℓi voorkomt. Dat betek<strong>en</strong>t, dat voor elke driehoek t<strong>en</strong>minste één <strong>van</strong> de kant<strong>en</strong> die tuss<strong>en</strong> de<br />

driehoek<strong>en</strong> <strong>en</strong> de knop<strong>en</strong> lop<strong>en</strong> aan beide kant<strong>en</strong> e<strong>en</strong> ℓi hebb<strong>en</strong> staan. We nem<strong>en</strong> <strong>van</strong> deze knop<strong>en</strong> deg<strong>en</strong>e<br />

die bij de par<strong>en</strong> hoort op in de vertex cover, alsmede de andere twee knop<strong>en</strong> <strong>van</strong> de driehoek. We hebb<strong>en</strong> nu<br />

<strong>van</strong> de par<strong>en</strong> (zonodig door aan te vull<strong>en</strong>) één knoop, <strong>en</strong> <strong>van</strong> elke driehoek twee knop<strong>en</strong> in de vertex cover.<br />

Totaal dus n + 2m knop<strong>en</strong>. Er geldt dat elke kant in de par<strong>en</strong> <strong>en</strong> de driehoek<strong>en</strong> e<strong>en</strong> eindpunt in de vertex<br />

cover heeft. Van de kant<strong>en</strong> die tuss<strong>en</strong> de par<strong>en</strong> <strong>en</strong> de driehoek<strong>en</strong> lop<strong>en</strong> zit of het eindpunt in de driehoek in<br />

de vertex cover, of het eindpunt in het paar, zodat onze vertex cover volledig is.<br />

Stel omgekeerd dat onze graaf e<strong>en</strong> vertex cover <strong>van</strong> grootte n + 2m heeft. Van elk paar zit t<strong>en</strong>minste (<strong>en</strong><br />

ook t<strong>en</strong> hoogste) één punt in de vertex cover <strong>en</strong> <strong>van</strong> elke driehoek zitt<strong>en</strong> t<strong>en</strong> minste (<strong>en</strong> ook t<strong>en</strong> hoogste)<br />

twee punt<strong>en</strong> in de vertex cover. Alle kant<strong>en</strong> hebb<strong>en</strong> per definitie t<strong>en</strong>minste één eindpunt in de vertex cover.<br />

Omdat <strong>van</strong> elke driehoek t<strong>en</strong>minste één punt niet in de vertex cover zit, moet het wel zo zijn dat voor de<br />

kant die tuss<strong>en</strong> dit punt <strong>en</strong> de par<strong>en</strong> loopt het andere eindpunt in de vertex cover zit. We kunn<strong>en</strong> dus bij de<br />

par<strong>en</strong> n punt<strong>en</strong> vind<strong>en</strong> (<strong>van</strong> ieder paar één), zodat deze n punt<strong>en</strong> sam<strong>en</strong> verbond<strong>en</strong> zijn met alle driehoek<strong>en</strong>.<br />

Dat wil zegg<strong>en</strong> dat de optred<strong>en</strong>s waarmee deze n punt<strong>en</strong> gelabeled zijn in alle Cj voorkom<strong>en</strong> of dat we door<br />

deze optred<strong>en</strong>s waar te mak<strong>en</strong>, de hele formule waar kunn<strong>en</strong> mak<strong>en</strong>.<br />

Voorbeeld 6.5.1: Laat gegev<strong>en</strong> zijn de formule F (x1, x2, x3) = (x1 ∨ x2 ∨ x3) ∧ (x1 ∨ x2 ∨ x3). De reductie<br />

transformeert dit tot de volg<strong>en</strong>de graaf.<br />

• • • • • •<br />

• •<br />

• • • •<br />

In deze graaf hebb<strong>en</strong> we kant<strong>en</strong> die tuss<strong>en</strong> twee del<strong>en</strong> <strong>van</strong> de graaf lop<strong>en</strong> (<strong>van</strong> de variabel<strong>en</strong> naar de<br />

zinn<strong>en</strong>) onderbrok<strong>en</strong> getek<strong>en</strong>d voor de duidelijkheid. ✷<br />

Nu we de volledigheid <strong>van</strong> VERTEX COVER hebb<strong>en</strong> aangetoond, kunn<strong>en</strong> we ook de volledigheid <strong>van</strong><br />

INDEPENDENT SET <strong>en</strong> CLIQUE bewijz<strong>en</strong>. Eerst de probleemdefinities.<br />

naam: INDEPENDENT SET<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G = (V, E) <strong>en</strong> e<strong>en</strong> getal k<br />

gevraagd: Bestaat er e<strong>en</strong> deelverzameling V ′ ⊆ V met |V ′ | ≥ k zo dat tuss<strong>en</strong> de knop<strong>en</strong> <strong>van</strong> V ′ ge<strong>en</strong><br />

kant zit ({(v, v ′ ) : v, v ′ ∈ V ′ } ∩ E = ∅)?<br />

naam: CLIQUE<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G = (V, E) <strong>en</strong> e<strong>en</strong> getal k<br />

gevraagd: Bestaat er e<strong>en</strong> deelverzameling V ′ ⊆ V met |V ′ | ≥ k zó dat tuss<strong>en</strong> elk paar knop<strong>en</strong> in V ′<br />

e<strong>en</strong> kant zit (G|V ′ is e<strong>en</strong> volledige ondergraaf)?<br />

Eerst merk<strong>en</strong> we op dat beide problem<strong>en</strong> in NP zitt<strong>en</strong>. Gegev<strong>en</strong> e<strong>en</strong> collectie <strong>van</strong> k knop<strong>en</strong> is het immers<br />

vrij e<strong>en</strong>voudig te controler<strong>en</strong> dat tuss<strong>en</strong> elk paar ge<strong>en</strong>, of juist wel, e<strong>en</strong> kant aanwezig is. Vervolg<strong>en</strong>s zi<strong>en</strong><br />

we in dat de reductie tuss<strong>en</strong> de beide problem<strong>en</strong> ook bijzonder simpel is. Als afbeelding <strong>van</strong> G nem<strong>en</strong> we<br />

111


in beide gevall<strong>en</strong> de graaf G, de complem<strong>en</strong>taire graaf. In de complem<strong>en</strong>taire graaf is elke kant verwijderd<br />

<strong>en</strong> tuss<strong>en</strong> elk paar knop<strong>en</strong> waartuss<strong>en</strong> ge<strong>en</strong> kant liep is e<strong>en</strong> kant aangebracht. Ofwel als G = (V, E), dan is<br />

G = (V, E) met E = V × V − E. Elke indep<strong>en</strong>d<strong>en</strong>t set in G wordt e<strong>en</strong> clique in G <strong>en</strong> omgekeerd.<br />

De reductie <strong>van</strong> VERTEX COVER naar INDEPENDENT SET is ook e<strong>en</strong> bijzonder simpele reductie.<br />

Hiervoor verander<strong>en</strong> we de graaf niet e<strong>en</strong>s, we vind<strong>en</strong> alle<strong>en</strong> e<strong>en</strong> andere waarde voor k. Immers, als er e<strong>en</strong><br />

verzameling V ′ met cardinaliteit hoogst<strong>en</strong>s k is zo dat alle kant<strong>en</strong> e<strong>en</strong> eindpunt in V ′ hebb<strong>en</strong>, dan heeft ge<strong>en</strong><br />

kant beide eindpunt<strong>en</strong> in V − V ′ , ofwel V − V ′ is e<strong>en</strong> indep<strong>en</strong>d<strong>en</strong>t set. Dus e<strong>en</strong> graaf G heeft e<strong>en</strong> VERTEX<br />

COVER <strong>van</strong> grootte hoogst<strong>en</strong>s k dan <strong>en</strong> slechts dan als G e<strong>en</strong> indep<strong>en</strong>d<strong>en</strong>t set heeft <strong>van</strong> grootte minst<strong>en</strong>s<br />

|V | − k.<br />

Rondjes in Graf<strong>en</strong><br />

Graf<strong>en</strong> word<strong>en</strong> vaak gebruikt om geografische problem<strong>en</strong> te repres<strong>en</strong>ter<strong>en</strong>, waarbij pad<strong>en</strong> in graf<strong>en</strong> dan de<br />

bereikbaarheidsrelatie aangev<strong>en</strong>. In het eerste deel <strong>van</strong> deze tekst hebb<strong>en</strong> we ons al afgevraagd hoe moeilijk<br />

het is om de kortste weg tuss<strong>en</strong> twee punt<strong>en</strong> te vind<strong>en</strong>. Dat bleek e<strong>en</strong> algoritmisch relatief e<strong>en</strong>voudig probleem<br />

te zijn. Hier zull<strong>en</strong> we inzi<strong>en</strong> dat het vind<strong>en</strong> <strong>van</strong> de langste weg tuss<strong>en</strong> twee punt<strong>en</strong> algoritmisch vele mal<strong>en</strong><br />

moeilijker ligt. E<strong>en</strong> rondje langs alle punt<strong>en</strong> in e<strong>en</strong> graaf vind<strong>en</strong> zonder in herhaling te vall<strong>en</strong>, zull<strong>en</strong> we<br />

ler<strong>en</strong> k<strong>en</strong>n<strong>en</strong> als e<strong>en</strong> NP-volledig probleem. Het komt vaker voor dat moeilijke <strong>en</strong> e<strong>en</strong>voudige algoritmische<br />

problem<strong>en</strong> dicht bij elkaar ligg<strong>en</strong>. Zo zag<strong>en</strong> wij bijvoorbeeld dat 3-SAT e<strong>en</strong> NP-volledig probleem is, omdat<br />

we elke formule in conjunctieve normaalvorm kunn<strong>en</strong> terugbr<strong>en</strong>g<strong>en</strong> tot e<strong>en</strong> formule waarin elke zin slechts<br />

drie optred<strong>en</strong>s <strong>van</strong> variabel<strong>en</strong> k<strong>en</strong>t. De oplett<strong>en</strong>de lezer zal hebb<strong>en</strong> opgemerkt dat de daar gepres<strong>en</strong>teerde<br />

reductie niet kan word<strong>en</strong> doorgezet totdat elke zin nog maar twee optred<strong>en</strong>s <strong>van</strong> variabel<strong>en</strong> heeft. Dit heeft<br />

e<strong>en</strong> diepere betek<strong>en</strong>is, zoals we in de opgav<strong>en</strong> zull<strong>en</strong> zi<strong>en</strong>. Ook in deze sectie zijn er subtiele verschill<strong>en</strong><br />

tuss<strong>en</strong> effici<strong>en</strong>t oplosbare <strong>en</strong> NP-volledige problem<strong>en</strong>. Het verschil tuss<strong>en</strong> kortste pad/langste pad noemd<strong>en</strong><br />

we al, maar we will<strong>en</strong> toch ook het voorbeeld <strong>van</strong> e<strong>en</strong> volledige <strong>en</strong>kelvoudige cykel die alle kant<strong>en</strong> slechts 1<br />

keer gebruikt hier niet voorbijlop<strong>en</strong>.<br />

naam: EULER CYCLE<br />

gegev<strong>en</strong>: Gegev<strong>en</strong> e<strong>en</strong> graaf G<br />

gevraagd: Is het mogelijk e<strong>en</strong> pad te vind<strong>en</strong> dat alle kant<strong>en</strong> precies één keer gebruikt?<br />

In het stadje Königsberg (teg<strong>en</strong>woordig Kalingrad) in voormalig oost Pruis<strong>en</strong> war<strong>en</strong> zev<strong>en</strong> brugg<strong>en</strong> over<br />

de rivier die door de stad loopt. De burgers wandeld<strong>en</strong> vaak op zondagmiddag <strong>van</strong> één <strong>van</strong> de oevers naar de<br />

eiland<strong>en</strong> <strong>en</strong> dan naar de andere oever <strong>en</strong> dan terug. De overtuiging heerste dat het onmogelijk is om al deze<br />

zev<strong>en</strong> brugg<strong>en</strong> over te gaan zonder één <strong>van</strong> de brugg<strong>en</strong> twee keer te gebruik<strong>en</strong> (zie Figuur 6.5.1). Euler loste<br />

niet all<strong>en</strong> dit probleem op, maar ook het algem<strong>en</strong>ere geval, door te bewijz<strong>en</strong> dat e<strong>en</strong> ronde in e<strong>en</strong> graaf die elke<br />

kant precies één keer gebruikt (<strong>van</strong>af to<strong>en</strong> Eulerronde g<strong>en</strong>oemd) alle<strong>en</strong> mogelijk is als elke knoop in de graaf<br />

e<strong>en</strong> ev<strong>en</strong> graad heeft. Het bewijs is e<strong>en</strong> e<strong>en</strong>voudig inductiebewijs dat in elke graf<strong>en</strong>theorietekst gevond<strong>en</strong><br />

kan word<strong>en</strong>. Voor de complexiteit <strong>van</strong> het probleem EULER CYCLE betek<strong>en</strong>t dit dat het daarmee e<strong>en</strong><br />

deterministisch polynomiale tijd oplosbaar probleem geword<strong>en</strong> is. Immers, we hoev<strong>en</strong> slechts te controler<strong>en</strong><br />

of elke knoop in de graaf e<strong>en</strong> ev<strong>en</strong> graad heeft.<br />

Het probleem wordt echter ine<strong>en</strong>s veel moeilijker als we in de definitie het woord kant door knoop<br />

ver<strong>van</strong>g<strong>en</strong>.<br />

naam: HAMILTON CIRCUIT<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G = (V, E)<br />

gevraagd: Is het mogelijk e<strong>en</strong> permutatie <strong>van</strong> de knop<strong>en</strong> te vind<strong>en</strong> vi1 , . . . , vin zo dat deze volgorde e<strong>en</strong><br />

<strong>en</strong>kelvoudig pad langs alle knop<strong>en</strong> voorstelt?<br />

Opnieuw merk<strong>en</strong> we eerst op dat dit e<strong>en</strong> probleem in NP is. Immers gegev<strong>en</strong> zo’n permutatie is het<br />

e<strong>en</strong>voudig te controler<strong>en</strong> dat elke knoop precies één keer voorkomt <strong>en</strong> dat tuss<strong>en</strong> twee ope<strong>en</strong>volg<strong>en</strong>de knop<strong>en</strong><br />

in de rij e<strong>en</strong> kant in G zit.<br />

Het probleem is echter ook NP-volledig. Hiertoe beschrijv<strong>en</strong> we e<strong>en</strong> deterministisch polynomiale tijd<br />

begr<strong>en</strong>sde reductie <strong>van</strong> het probleem VERTEX COVER.<br />

112


Figuur 6.5: Euler’s eiland<strong>en</strong> in Königsberg<br />

Figuur 6.6: Deelgraaf voor kant<strong>en</strong> uit G.<br />

Gegev<strong>en</strong> e<strong>en</strong> graaf G = (V, E) <strong>en</strong> e<strong>en</strong> getal k, mak<strong>en</strong> we e<strong>en</strong> graaf G ′ met de eig<strong>en</strong>schap dat als G e<strong>en</strong><br />

vertex cover heeft <strong>van</strong> grootte hoogst<strong>en</strong>s k, dan heeft G ′ e<strong>en</strong> Hamilton circuit. Onze graaf G ′ bestaat uit<br />

k zog<strong>en</strong>oemde keuzeknop<strong>en</strong> die ons elk uit de verzameling knop<strong>en</strong> <strong>van</strong> G e<strong>en</strong> knoop lat<strong>en</strong> kiez<strong>en</strong>. Verder<br />

voer<strong>en</strong> we voor elke kant in G e<strong>en</strong> deelgraafje <strong>van</strong> G ′ in, zoals in Figuur 6.6.<br />

Deze deelgraafjes kunn<strong>en</strong> op precies drie manier<strong>en</strong> doorlop<strong>en</strong> word<strong>en</strong> zonder e<strong>en</strong> knoop over te slaan <strong>en</strong><br />

zonder e<strong>en</strong> knoop twee keer aan te do<strong>en</strong>. Zie figuur 6.7<br />

1. Je kunt eerst e<strong>en</strong> keer links langs alle onder elkaar ligg<strong>en</strong>de knop<strong>en</strong> lop<strong>en</strong> <strong>en</strong> vervolg<strong>en</strong>s bij e<strong>en</strong> volg<strong>en</strong>de<br />

keer rechts langs alle knop<strong>en</strong>.<br />

2. Je kunt de eerste twee knop<strong>en</strong> <strong>van</strong> bov<strong>en</strong> <strong>van</strong> de linkerkant pakk<strong>en</strong>, vervolg<strong>en</strong>s naar de eerste knoop<br />

rechtsbov<strong>en</strong> overstek<strong>en</strong>, dan alle knop<strong>en</strong> aan de rechterkant langslop<strong>en</strong>, <strong>en</strong> t<strong>en</strong>slotte naar de derde<br />

knoop linksbov<strong>en</strong> overstek<strong>en</strong> <strong>en</strong> de laatste twee knop<strong>en</strong> <strong>van</strong> de linkerkant me<strong>en</strong>em<strong>en</strong>.<br />

3. Je kunt het bov<strong>en</strong>staande pad ook gespiegeld volg<strong>en</strong>. Dus eerst de twee bov<strong>en</strong>ste knop<strong>en</strong> rechts, dan<br />

het hele linkerrijtje <strong>en</strong> vervolg<strong>en</strong>s de laatste twee knop<strong>en</strong> rechts.<br />

113


.<br />

.<br />

• •<br />

• •<br />

• •<br />

• •<br />

.<br />

.<br />

.<br />

��<br />

•<br />

��<br />

•<br />

��<br />

•<br />

��<br />

•<br />

��<br />

.<br />

.<br />

��<br />

•<br />

��<br />

•<br />

��<br />

•<br />

��<br />

•<br />

��<br />

.<br />

��<br />

•<br />

��<br />

•<br />

•<br />

��<br />

•<br />

��<br />

��<br />

. . . .<br />

1 2 3<br />

��<br />

.<br />

•<br />

��<br />

•<br />

��<br />

•<br />

��<br />

•<br />

Figuur 6.7: 3 manier<strong>en</strong> om de deelgraaf te doorlop<strong>en</strong><br />

Als zo’n deelgraaf e<strong>en</strong> kant (v, w) repres<strong>en</strong>teert, verbind<strong>en</strong> we in de hele graaf alle deelgraf<strong>en</strong> die e<strong>en</strong><br />

kant (v, w ′ ) repres<strong>en</strong>ter<strong>en</strong> in e<strong>en</strong> lang pad met de linkerkant <strong>van</strong> deze deelgraaf. Ev<strong>en</strong>zo verbind<strong>en</strong> we alle<br />

deelgraf<strong>en</strong> die e<strong>en</strong> kant (v ′ , w) voorstell<strong>en</strong> in e<strong>en</strong> lang pad met de rechterkant <strong>van</strong> deze graaf. E<strong>en</strong> knoop<br />

wordt zo geïd<strong>en</strong>tificeerd met e<strong>en</strong> pad in de graaf. T<strong>en</strong>slotte zijn al dit soort pad<strong>en</strong> verbond<strong>en</strong> met de k keuze<br />

knop<strong>en</strong>.<br />

Als nu G e<strong>en</strong> vertex cover <strong>van</strong> grootte k heeft, kun je in keuzeknoop 1 beginn<strong>en</strong> <strong>en</strong> vervolg<strong>en</strong>s alle<br />

deelgraf<strong>en</strong> doorlop<strong>en</strong> die e<strong>en</strong> eindpunt in de vertex cover hebb<strong>en</strong> (dus alle kant<strong>en</strong>) op drie manier<strong>en</strong>:<br />

1. Als beide eindpunt<strong>en</strong> in de vertex cover zitt<strong>en</strong>, dan wordt de deelgraaf twee keer doorlop<strong>en</strong>.<br />

.<br />

•<br />

��<br />

•<br />

��<br />

•<br />

��<br />

•<br />

2. Als het linkereindpunt in de vertexcover zit, kom<strong>en</strong> we aan de linkerkant binn<strong>en</strong>, nem<strong>en</strong> vervolg<strong>en</strong>s<br />

alle knop<strong>en</strong> op <strong>en</strong> gaan we er ook aan de linkerkant weer uit.<br />

3. Idem voor de rechterkant.<br />

Omgekeerd, als G ′ e<strong>en</strong> Hamilton circuit heeft kan elke deelgraaf maar op één <strong>van</strong> de drie manier<strong>en</strong><br />

doorlop<strong>en</strong> word<strong>en</strong>. Aan de manier waarop e<strong>en</strong> deelgraaf doorlop<strong>en</strong> wordt, kunn<strong>en</strong> we zi<strong>en</strong> welke knop<strong>en</strong> in<br />

de vertex cover hor<strong>en</strong>. Het feit dat de hele graaf doorlop<strong>en</strong> wordt, garandeert e<strong>en</strong> vertex cover <strong>van</strong> grootte<br />

hoogst<strong>en</strong>s k.<br />

Als we e<strong>en</strong>maal de NP-volledigheid <strong>van</strong> Hamilton circuit hebb<strong>en</strong> aangetoond kunn<strong>en</strong> we <strong>van</strong> daaruit weer<br />

de NP-volledigheid <strong>van</strong> het beroemde handelsreizigerprobleem aanton<strong>en</strong>.<br />

naam: HANDELSREIZIGER<br />

gegev<strong>en</strong>: E<strong>en</strong> volledige graaf K = (V, E), e<strong>en</strong> gewichtsfunctie w : E ↦→ R, <strong>en</strong> e<strong>en</strong> getal B<br />

gevraagd: Heeft K e<strong>en</strong> Hamilton circuit waar<strong>van</strong> het totale gewicht kleiner dan of gelijk is aan B<br />

Ook dit is e<strong>en</strong> probleem in NP, want als ons e<strong>en</strong> Hamilton circuit gegev<strong>en</strong> wordt, is het e<strong>en</strong>voudig te<br />

controler<strong>en</strong> dat het inderdaad e<strong>en</strong> Hamilton circuit is, <strong>en</strong> na optell<strong>en</strong> <strong>van</strong> de gewicht<strong>en</strong> te constater<strong>en</strong> dat<br />

het totale gewicht kleiner dan of gelijk aan B is.<br />

Het is echter ook e<strong>en</strong> NP-volledig probleem. Om dit te lat<strong>en</strong> zi<strong>en</strong> gebruik<strong>en</strong> we de volg<strong>en</strong>de reductie <strong>van</strong><br />

Hamilton circuit. Laat e<strong>en</strong> graaf G = (V, E) gegev<strong>en</strong> zijn op n knop<strong>en</strong>. E<strong>en</strong> Hamilton circuit in G heeft<br />

precies n kant<strong>en</strong>. We gev<strong>en</strong> alle kant<strong>en</strong> in G gewicht 1, <strong>en</strong> mak<strong>en</strong> G vervolg<strong>en</strong>s volledig. Alle nieuwe kant<strong>en</strong><br />

krijg<strong>en</strong> gewicht n + 1. Noem de nieuwe graaf K. Als nu gevraagd wordt “Heeft K e<strong>en</strong> Hamilton circuit<br />

114<br />

��<br />

��<br />

.<br />

��<br />

•<br />

��<br />

•<br />

•<br />

��<br />

•<br />

��<br />

.


waar<strong>van</strong> het totale gewicht kleiner dan of gelijk is aan n, dan kan het antwoord alle<strong>en</strong> maar bevestig<strong>en</strong>d<br />

zijn indi<strong>en</strong> ook G e<strong>en</strong> Hamilton circuit heeft. Omgekeerd: als G e<strong>en</strong> Hamilton circuit heeft, dan vorm<strong>en</strong> de<br />

kant<strong>en</strong> in dit Hamilton circuit e<strong>en</strong> Hamilton circuit in K waar<strong>van</strong> het totale gewicht precies n is.<br />

We concluder<strong>en</strong> dus dat K e<strong>en</strong> tour heeft <strong>van</strong> l<strong>en</strong>gte n dan <strong>en</strong> slechts dan als G e<strong>en</strong> Hamilton circuit<br />

heeft, of 〈K, n〉 ∈ TSP ⇔ G ∈ HAM.<br />

Pass<strong>en</strong> <strong>en</strong> Verdel<strong>en</strong><br />

” Met pass<strong>en</strong> <strong>en</strong> met<strong>en</strong> wordt de meeste tijd verslet<strong>en</strong>”, is e<strong>en</strong> oude wijsheid. Uit e<strong>en</strong> berg onderdel<strong>en</strong><br />

waarbij ge<strong>en</strong> nette bouwtek<strong>en</strong>ing gegev<strong>en</strong> is, is het lastig iets zinnigs sam<strong>en</strong> te stell<strong>en</strong>, zo dat zoveel mogelijk<br />

onderdel<strong>en</strong> gebruikt word<strong>en</strong>. Iedere<strong>en</strong> die wel e<strong>en</strong>s e<strong>en</strong> meubelstuk bij e<strong>en</strong> doe het zelf zaak gekocht heeft,<br />

met lego gespeeld heeft, of e<strong>en</strong> legpuzzel heeft opgelost, k<strong>en</strong>t dit probleem. In dit gedeelte zull<strong>en</strong> we e<strong>en</strong><br />

aantal <strong>van</strong> dit soort problem<strong>en</strong> bekijk<strong>en</strong>. E<strong>en</strong> masterprobleem is dat <strong>van</strong> het legg<strong>en</strong> <strong>van</strong> legpuzzels. We zull<strong>en</strong><br />

zi<strong>en</strong> dat e<strong>en</strong> sterke vere<strong>en</strong>voudiging <strong>van</strong> dit probleem nog NP-volledig is. Het wordt als volgt geformuleerd.<br />

naam: BEGRENSDE BETEGELING<br />

gegev<strong>en</strong>: E<strong>en</strong> N × N vierkant met kleur<strong>en</strong> aan de rand <strong>en</strong> e<strong>en</strong> verzameling tegeltyp<strong>en</strong>, met e<strong>en</strong> 1 × 1<br />

oppervlakte die ook gekleurde rand<strong>en</strong> hebb<strong>en</strong><br />

gevraagd: Is het mogelijk het vierkant zo vol te legg<strong>en</strong>, dat tegels niet gedraaid word<strong>en</strong> <strong>en</strong> aanligg<strong>en</strong>de<br />

tegels langs aanligg<strong>en</strong>de rand<strong>en</strong> dezelfde kleur hebb<strong>en</strong>?<br />

Uiteraard is ook BEGRENSDE BETEGELING e<strong>en</strong> probleem in NP immers, gegev<strong>en</strong> e<strong>en</strong> invulling <strong>van</strong><br />

het vierkant kunn<strong>en</strong> we gemakkelijk controler<strong>en</strong> dat dit vierkant aan alle eis<strong>en</strong> voldoet. BEGRENSDE<br />

BETEGELING is ook e<strong>en</strong> NP-volledig probleem. Om dit te bewijz<strong>en</strong> gebruik<strong>en</strong> we opnieuw het middel <strong>van</strong><br />

de master reductie. Gegev<strong>en</strong> e<strong>en</strong> willekeurige nondeterministische Turing machine M, e<strong>en</strong> polynoom p <strong>en</strong><br />

e<strong>en</strong> invoer x construer<strong>en</strong> we e<strong>en</strong> betegelingsprobleem dat e<strong>en</strong> oplossing heeft dan <strong>en</strong> slechts dan als M invoer<br />

x in t<strong>en</strong> hoogste p(|x|) stapp<strong>en</strong> kan accepter<strong>en</strong>.<br />

Om technische red<strong>en</strong><strong>en</strong> nem<strong>en</strong> we aan dat het programma <strong>van</strong> M zodanig is dat er ge<strong>en</strong> instructie in<br />

staat waar M zowel naar links als naar rechts kan beweg<strong>en</strong>. Dit is ge<strong>en</strong> beperking <strong>van</strong> de algeme<strong>en</strong>heid.<br />

Verder nem<strong>en</strong> we aan dat elke accepter<strong>en</strong>de berek<strong>en</strong>ing <strong>van</strong> M eindigt in de meest linker bandcel in toestand<br />

qF met onder de kop het blanco symbool. Verder zorg<strong>en</strong> we er met e<strong>en</strong> extra instructie voor dat de laatste<br />

configuratie <strong>van</strong> M zo vaak als nodig herhaald kan word<strong>en</strong>.<br />

De reductie gaat als volgt. We gebruik<strong>en</strong> kleur<strong>en</strong> die we de nam<strong>en</strong> gev<strong>en</strong> <strong>van</strong> achtere<strong>en</strong>volg<strong>en</strong>s de<br />

bandsymbol<strong>en</strong> si, de toestand<strong>en</strong> qi <strong>en</strong> de combinaties <strong>van</strong> toestand<strong>en</strong> <strong>en</strong> bandsymbol<strong>en</strong> 〈qi, sj〉. T<strong>en</strong>slotte<br />

hebb<strong>en</strong> we nog één speciale kleur die we “wit” (w) zull<strong>en</strong> noem<strong>en</strong>. Het vierkant dat moet word<strong>en</strong> gevuld<br />

heeft afmeting<strong>en</strong> p(|x|) × p(|x|). Nu gev<strong>en</strong> we de eerste n plaats<strong>en</strong> langs de rand de kleur die overe<strong>en</strong>komt<br />

met de symbol<strong>en</strong> <strong>van</strong> x, <strong>en</strong> langs de onderrand <strong>van</strong> het vierkant plaats<strong>en</strong> we in het eerste vakje de kleur<br />

〈qF , w〉. Nu gebruik<strong>en</strong> we de volg<strong>en</strong>de tegels:<br />

1. Voor elk bandsymbool si (inclusief si = w) hebb<strong>en</strong> we e<strong>en</strong> tegel die zowel aan de bov<strong>en</strong>rand als aan<br />

de b<strong>en</strong>ed<strong>en</strong>rand de kleur si heeft.<br />

2. Voor elke instructie qi, sj ↦→ qk, sℓR hebb<strong>en</strong> we e<strong>en</strong> tegel die aan de bov<strong>en</strong>rand de kleur 〈qi, sj〉 draagt,<br />

aan de onderrand de kleur sℓ <strong>en</strong> aan de rechterzijkant de kleur qk<br />

3. Idem voor elke instructie qi, sj ↦→ qk, sℓL, maar dan met de kleur qk aan de linkerzijkant.<br />

4. Voor elke tegel <strong>van</strong> de vorige twee typ<strong>en</strong> <strong>en</strong> elk bandsymbool si hebb<strong>en</strong> we e<strong>en</strong> tegel met aan de<br />

bov<strong>en</strong>rand de kleur si, aan de linker (resp. rechter) zijkant de kleur qk <strong>en</strong> aan de onderrand de kleur<br />

〈qk, si〉.<br />

Als er nu e<strong>en</strong> berek<strong>en</strong>ing <strong>van</strong> M bestaat die accepteert in p(|x|) stapp<strong>en</strong>, dan kunn<strong>en</strong> we uit de achtere<strong>en</strong>volg<strong>en</strong>de<br />

configuraties <strong>van</strong> M e<strong>en</strong> kleuring <strong>van</strong> het vierkant aflez<strong>en</strong>. Omgekeerd definieert elke kleuring<br />

<strong>van</strong> het vierkant ook één op één e<strong>en</strong> accepter<strong>en</strong>de berek<strong>en</strong>ing <strong>van</strong> M <strong>van</strong> l<strong>en</strong>gte precies p(|x|).<br />

115


De NP-volledigheid <strong>van</strong> BEGRENSDE BETEGELING kunn<strong>en</strong> we gebruik<strong>en</strong> om het volg<strong>en</strong>de probleem<br />

in de rij verdeelproblem<strong>en</strong> NP-volledig te bewijz<strong>en</strong>. Het gaat hier om e<strong>en</strong> gegev<strong>en</strong> aantal deelverzameling<strong>en</strong><br />

waarmee we e<strong>en</strong> gebied will<strong>en</strong> overdekk<strong>en</strong> waarbij het aantal plaats<strong>en</strong> dat dubbel gedekt wordt zo klein<br />

mogelijk gehoud<strong>en</strong> wordt. E<strong>en</strong> bek<strong>en</strong>de toepassing <strong>van</strong> dit probleem is het rooster<strong>en</strong> <strong>van</strong> flight crews. Vliegtuig<strong>en</strong><br />

kunn<strong>en</strong> niet nadat ze geland zijn mete<strong>en</strong> weer opstijg<strong>en</strong>, omdat er allerlei technische controles moet<strong>en</strong><br />

word<strong>en</strong> uitgevoerd, het vliegtuig moet word<strong>en</strong> bijgetankt, soms moet word<strong>en</strong> omgebouwd <strong>van</strong> passagiers naar<br />

vrachtvliegtuig <strong>en</strong>zovoort. Ev<strong>en</strong>zo kan de crew niet altijd mete<strong>en</strong> met hetzelfde of met e<strong>en</strong> ander vliegtuig<br />

weer opstijg<strong>en</strong> zodra ze geland zijn. Soms moet er word<strong>en</strong> geget<strong>en</strong> of word<strong>en</strong> overnacht of will<strong>en</strong> ze zomaar<br />

e<strong>en</strong> paar dag<strong>en</strong> vrij. Het gevolg hier<strong>van</strong> is dat vliegpersoneel vaak met e<strong>en</strong> vliegtuig <strong>van</strong> dezelfde of e<strong>en</strong><br />

andere maatschappij moet word<strong>en</strong> vervoerd naar e<strong>en</strong> andere luchthav<strong>en</strong> om daar weer e<strong>en</strong> vliegtuig te gaan<br />

bestur<strong>en</strong>. E<strong>en</strong> luchtvaartmaatschappij wil uiteraard zoveel mogelijk <strong>van</strong> de beschikbare stoel<strong>en</strong> verkop<strong>en</strong> <strong>en</strong><br />

dus graag zo weinig mogelijk <strong>van</strong> het eig<strong>en</strong> personeel vervoer<strong>en</strong>. Zaak is dus om de uit te voer<strong>en</strong> vlucht<strong>en</strong><br />

zoveel mogelijk te bezett<strong>en</strong> met één <strong>en</strong>kele crew. De andere constraint is natuurlijk dat elke vlucht wel<br />

minimaal één crew moet hebb<strong>en</strong>. In onze notatie wordt dit probleem (als beslissingsprobleem) als volgt<br />

geformuleerd.<br />

naam: EXACTE OVERDEKKING<br />

gegev<strong>en</strong>: E<strong>en</strong> universum U = {1, . . . , n} <strong>en</strong> e<strong>en</strong> verzameling deelverzameling<strong>en</strong> Si ⊆ U.<br />

gevraagd: Bestaat er e<strong>en</strong> indexverzameling I zó dat �<br />

i∈I Si = U <strong>en</strong> (∀i �= j ∈ I)[Si ∩ Sj = ∅]?<br />

Uiteraard is ook dit e<strong>en</strong> probleem in NP. Gegev<strong>en</strong> de indexverzameling kunn<strong>en</strong> we gemakkelijk controler<strong>en</strong><br />

dat elk elem<strong>en</strong>t <strong>van</strong> het universum precies één keer voorkomt. Het probleem is ook NP-volledig. Hiervoor<br />

producer<strong>en</strong> we e<strong>en</strong> reductie <strong>van</strong> begr<strong>en</strong>sde betegeling<strong>en</strong>. Gegev<strong>en</strong> e<strong>en</strong> begr<strong>en</strong>sd betegelingsprobleem met<br />

e<strong>en</strong> N × N vierkant <strong>en</strong> tegeltyp<strong>en</strong> Ti. We noter<strong>en</strong> e<strong>en</strong> verzameling kleur<strong>en</strong> HC die langs horizontale rand<strong>en</strong><br />

kunn<strong>en</strong> voorkom<strong>en</strong>, e<strong>en</strong> verzameling VC <strong>van</strong> kleur<strong>en</strong> die langs verticale rand<strong>en</strong> kunn<strong>en</strong> voorkom<strong>en</strong>. Nu<br />

bekijk<strong>en</strong> we de bov<strong>en</strong>rand <strong>van</strong> het vierkant <strong>en</strong> introducer<strong>en</strong> de verzameling RB = {〈〈0, i〉, ki〉 : ki is de i-de<br />

kleur langs de bov<strong>en</strong>rand }. Ev<strong>en</strong>zo voor de onderrand <strong>van</strong> het vierkant RO = {〈N + 1, i, HC − ki〉 : ki is<br />

de i-de kleur langs de onderrand }. Voor de linkerrand <strong>van</strong> het vierkant introducer<strong>en</strong> we de verzameling<br />

RL = {〈0, i, ki〉 : ki is de i-de kleur langs de linkerrand }. Voor de rechterrand <strong>van</strong> het vierkant introducer<strong>en</strong><br />

we de verzameling RR = {〈N + 1, i, VC − ki〉 : ki is de i-de kleur langs de rechterrand }. Tot slot: stel dat<br />

er e<strong>en</strong> tegeltype Tk is met kleur<strong>en</strong> bk, ok, ℓk, rk respectievelijk aan de bov<strong>en</strong>-, onder-, linker- <strong>en</strong> rechterkant.<br />

Dan introducer<strong>en</strong> we de verzameling<strong>en</strong> Tkij = {〈i, j, HC − bk〉, 〈i + 1, j, ok〉, 〈i, j, VC − ℓk〉, 〈i, j + 1, rk〉} voor<br />

i, j ∈ {1, . . . , N}. Het universum is U = {〈i, j, HC〉, 〈i, j, VC〉} voor i, j ∈ {1, . . . , N + 1}.<br />

Als het vierkant met tegels kan word<strong>en</strong> overdekt kunn<strong>en</strong> we aan het tegeltype Tk dat op plaats i, j ligt<br />

aflez<strong>en</strong> welke deelverzameling Tkij moet word<strong>en</strong> gekoz<strong>en</strong>. Aan de andere kant, als e<strong>en</strong> volledige overdekking<br />

kan word<strong>en</strong> gerealiseerd door verzameling<strong>en</strong> Tkij <strong>en</strong> Tk ′ i+1j in de overdekking te kiez<strong>en</strong>, dan betek<strong>en</strong>t dat,<br />

dat er tegels Tk <strong>en</strong> Tk ′ zijn die de kleur bk langs de onder, resp bov<strong>en</strong>rand hebb<strong>en</strong> <strong>en</strong> die dus op coordinat<strong>en</strong><br />

i, j <strong>en</strong> i + 1, j gelegd kunn<strong>en</strong> word<strong>en</strong> voor gegev<strong>en</strong> i <strong>en</strong> j, ofwel dat er e<strong>en</strong> kleuring <strong>van</strong> het vierkant mogelijk<br />

is.<br />

De volg<strong>en</strong>de twee problem<strong>en</strong> in de rij pass<strong>en</strong> <strong>en</strong> met<strong>en</strong> zijn koppelingsproblem<strong>en</strong>. We hebb<strong>en</strong> gegev<strong>en</strong><br />

dat bepaalde elem<strong>en</strong>t<strong>en</strong> in groep<strong>en</strong> kunn<strong>en</strong> voorkom<strong>en</strong>, maar natuurlijk is voor elk elem<strong>en</strong>t niet éénduidig<br />

bepaald in welke groep dit elem<strong>en</strong>t terechtkomt. Dit probleem is oorspronkelijk bek<strong>en</strong>d onder de naam<br />

” stabiele huwelijksprobleem”. In deze (ouderwetse) vorm ging het erom par<strong>en</strong> aan elkaar te koppel<strong>en</strong>, zodat<br />

de totale verzameling par<strong>en</strong> e<strong>en</strong> stabiele koppeling voor zou stell<strong>en</strong>. We hebb<strong>en</strong> dit probleem eerder gezi<strong>en</strong><br />

in 3.4.1 <strong>en</strong> daar gezi<strong>en</strong> dat het e<strong>en</strong> e<strong>en</strong>voudig oplosbaar probleem is. De situatie wordt heel anders wanneer<br />

we het probleem uitbreid<strong>en</strong> <strong>van</strong> par<strong>en</strong> naar trio’s. De complexiteit <strong>van</strong> het probleem springt dan ine<strong>en</strong>s <strong>van</strong><br />

P naar NP-volledig. We zett<strong>en</strong> de twee probleemstelling<strong>en</strong> ev<strong>en</strong> onder elkaar om te zi<strong>en</strong> hoe weinig de twee<br />

<strong>van</strong> elkaar verschill<strong>en</strong>.<br />

naam: MATCHING<br />

gegev<strong>en</strong>: U = {1, . . . , m}, m ≥ n <strong>en</strong> e<strong>en</strong> verzameling par<strong>en</strong> {Pi} m i=1 , Pi ∈ U × U<br />

gevraagd: Is er e<strong>en</strong> indexverzameling I met |I | = n zo dat elke u ∈ U precies één keer op elke coordinaatplaats<br />

voorkomt in �<br />

i∈I Pi?<br />

116


naam: 3-DIMENSIONAL MATCHING<br />

gegev<strong>en</strong>: U = {1, . . . , m}, m ≥ n <strong>en</strong> e<strong>en</strong> verzameling drietall<strong>en</strong> {Di} m i=1 , Di ∈ U × U × U<br />

gevraagd: Is er e<strong>en</strong> indexverzameling I, met |I | = n zo dat zo dat elke u ∈ U precies één keer op elke<br />

coordinaatplaats voorkomt in �<br />

i∈I Di ?<br />

Zoals vaker gebeurt bij de overgang <strong>van</strong> 2 naar 3—zoals we hierbov<strong>en</strong> gezi<strong>en</strong> hebb<strong>en</strong> bij SATISFIABILITY<br />

<strong>en</strong> zoals we verderop zull<strong>en</strong> zi<strong>en</strong> bij kleur<strong>en</strong>problem<strong>en</strong>—zi<strong>en</strong> we e<strong>en</strong> verandering <strong>van</strong> de complexiteit <strong>van</strong> het<br />

probleem <strong>van</strong> do<strong>en</strong>lijk naar ondo<strong>en</strong>lijk. De bov<strong>en</strong>gr<strong>en</strong>s voor het probleem blijft polynomiaal. Immers, 3-<br />

DIMENSIONAL MATCHING is e<strong>en</strong> probleem in NP. Wanneer ons zo’n indexverzameling gegev<strong>en</strong> wordt,<br />

kunn<strong>en</strong> we gemakkelijk nagaan dat voor alledrie de coordinat<strong>en</strong> de projectie <strong>van</strong> de verzamgeling drietall<strong>en</strong><br />

op die coordinaat e<strong>en</strong> permutatie <strong>van</strong> de getall<strong>en</strong> 1, . . . n is. Dat 3-DIMENSIONAL MATCHING ook e<strong>en</strong> NPvolledig<br />

probleem is ton<strong>en</strong> we aan door e<strong>en</strong> reductie <strong>van</strong> EXACTE OVERDEKKING naar 3-DIMENSIONAL<br />

MATCHING te gev<strong>en</strong>.<br />

Gegev<strong>en</strong> e<strong>en</strong> exact overdekkingsprobleem met U = {1, . . . , n} met verzameling<strong>en</strong> Si. We gaan e<strong>en</strong><br />

verzameling drietall<strong>en</strong> D <strong>en</strong> e<strong>en</strong> universum T mak<strong>en</strong>, zó dat als e<strong>en</strong> deelverzameling <strong>van</strong> D exact T × T × T<br />

overdekt, we uit die overdekking e<strong>en</strong> deel <strong>van</strong> de verzameling<strong>en</strong> Si kunn<strong>en</strong> selecter<strong>en</strong> dat exact U overdekt.<br />

Allereerst definier<strong>en</strong> we par<strong>en</strong> 〈i, j〉, voor alle i <strong>en</strong> j waarvoor i in Sj zit. Al deze par<strong>en</strong> vorm<strong>en</strong> de verzameling<br />

T . Verder lat<strong>en</strong> we α(i) de minimale 〈i, j〉 zijn waarvoor er zo e<strong>en</strong> paar 〈i, j〉 bestaat. Tot slot hebb<strong>en</strong> we<br />

nog e<strong>en</strong> afbeelding π nodig die voor vaste j steeds e<strong>en</strong> cyclische permutatie is <strong>van</strong> Sj. Dus als we e<strong>en</strong><br />

paar 〈i1, j〉 hebb<strong>en</strong>, dan is π(〈i1, j〉) het paar 〈i2, j〉 waarbij i2 het elem<strong>en</strong>t in Sj is dat volgt op i1. De<br />

permutatie π loopt zo de hele verzameling Sj door, todat we weer bij i1 terug zijn. Nu definier<strong>en</strong> we<br />

drietall<strong>en</strong> D = {(α(i), 〈i, j〉, 〈i, j〉)} ∪ {(β, 〈i, j〉, π(〈i, j〉) : β ∈ T ∧ β �= α(〈i, j〉)}.<br />

De bewering is nu dat er e<strong>en</strong> deelverzameling <strong>van</strong> deze drietall<strong>en</strong> bestaat die T × T × T overdekt als <strong>en</strong><br />

alle<strong>en</strong> als er e<strong>en</strong> deel <strong>van</strong> de Sj bestaat dat exact U overdekt. Dus lat<strong>en</strong> we maar e<strong>en</strong>s aannem<strong>en</strong> dat er zo’n<br />

verzameling drietall<strong>en</strong> bestaat. Allereerst moet<strong>en</strong> de elem<strong>en</strong>t<strong>en</strong> α(i), allemaal in de eerste coordinaat <strong>van</strong><br />

T × T × T geraakt word<strong>en</strong>, dus we moet<strong>en</strong> voldo<strong>en</strong>de par<strong>en</strong> uit het eerste deel <strong>van</strong> D kiez<strong>en</strong>. Die word<strong>en</strong><br />

allemaal met één of ander paar 〈i, j〉 in de tweede coordinaat <strong>en</strong> hetzelfde paar 〈i, j〉 in de derde coordinaat<br />

gekoz<strong>en</strong>. We bewer<strong>en</strong> dat de verzameling <strong>van</strong> alle j’s die op deze manier gekoz<strong>en</strong> wordt zo is dat de Sj e<strong>en</strong><br />

exacte overdekking vorm<strong>en</strong> <strong>van</strong> U. Het is duidelijk dat de ver<strong>en</strong>iging <strong>van</strong> de Sj de verzameling U overdekt,<br />

het is dus voldo<strong>en</strong>de te bewijz<strong>en</strong> dat de zo gekoz<strong>en</strong> Sj e<strong>en</strong> onderling lege doorsnede hebb<strong>en</strong>. Stel dus maar<br />

dat we e<strong>en</strong> paar 〈i, j〉 <strong>en</strong> e<strong>en</strong> paar 〈i ′ , j ′ 〉 kiez<strong>en</strong> zo dat Sj ∩ Sj ′ �= ∅. Neem aan dat Sj ∩ Sj ′ ⊃ {k}. Het<br />

drietal (α(k), 〈k, ℓ〉, 〈k, ℓ〉) kan zo gekoz<strong>en</strong> word<strong>en</strong> dat ℓ = j of ℓ = j ′ , maar niet allebei. Lat<strong>en</strong> we aannem<strong>en</strong><br />

dat 〈k, j ′ 〉 gekoz<strong>en</strong> wordt. Aangezi<strong>en</strong> k ∈ Sj zal ook het paar 〈k, j〉 erg<strong>en</strong>s in de eerste, tweede <strong>en</strong> derde<br />

coordinaat moet<strong>en</strong> optred<strong>en</strong>. In het bijzonder is <strong>van</strong> belang dat het in de tweede coordinaat optreed. Als<br />

we namelijk 〈k, j〉 in de tweede coordinaat erg<strong>en</strong>s kiez<strong>en</strong>, dan moet de derde coordinaat <strong>van</strong> dit drietal<br />

gelijk zijn aan π(〈k, j〉). Immers we kunn<strong>en</strong> dit paar niet meer met α(k) in de eerste coordinaat kunn<strong>en</strong><br />

kiez<strong>en</strong>. Dit is echter e<strong>en</strong> paar 〈k ′ , j〉 waarbij k ′ het elem<strong>en</strong>t <strong>van</strong> Sj is dat volgt op k. Dit betek<strong>en</strong>t dat ook<br />

(α(k ′ ), 〈k ′ , j〉, 〈k ′ , j〉) niet in de overdekking met drietall<strong>en</strong> gekoz<strong>en</strong> kan word<strong>en</strong> <strong>en</strong> dus dat ook 〈k ′ , j〉 alle<strong>en</strong><br />

in de tweede coordinaat door de overdekking kan word<strong>en</strong> geraakt door e<strong>en</strong> drietal (β, 〈k ′ , j〉, π(〈k ′ , j〉). Zo<br />

voortgaande schakel<strong>en</strong> we achtere<strong>en</strong>volg<strong>en</strong>s alle elem<strong>en</strong>t<strong>en</strong> <strong>van</strong> Sj uit als kandidaat om op te tred<strong>en</strong> in e<strong>en</strong><br />

drietal (α(r), 〈r, j〉, 〈r, j〉), ofwel Sj is niet e<strong>en</strong> verzameling die in de overdekking is gekoz<strong>en</strong>. Teg<strong>en</strong>spraak.<br />

Als omgekeerd e<strong>en</strong> overdekking <strong>van</strong> de Sj bestaat die U overdekt, dan kunn<strong>en</strong> we voor elke i die in e<strong>en</strong> Sj<br />

zit, het bijbehor<strong>en</strong>de drietal (α(i), 〈i, j〉, 〈i, j〉) kiez<strong>en</strong>. Het feit dat de gekoz<strong>en</strong> Sj e<strong>en</strong> lege doorsnede hebb<strong>en</strong>,<br />

maakt dat we de rest <strong>van</strong> T × T × T kunn<strong>en</strong> overdekk<strong>en</strong> met drietall<strong>en</strong> <strong>van</strong> de vorm (〈i, j〉, 〈i, j〉, π(〈i, j〉).<br />

Lat<strong>en</strong> we dit ingewikkelde verhaal toelicht<strong>en</strong> aan de hand <strong>van</strong> e<strong>en</strong> voorbeeld.<br />

Voorbeeld 6.5.2: Stel dat het universum U = {1, . . . , 5} <strong>en</strong> lat<strong>en</strong> de verzameling<strong>en</strong> Si als volgt gegev<strong>en</strong><br />

zijn.<br />

S1 = {1, 4, 5}<br />

S2 = {2, 3}<br />

S3 = {1, 3, 5}<br />

S4 = {2, 5}<br />

117


Merk op dat S1 <strong>en</strong> S2 sam<strong>en</strong> e<strong>en</strong> exacte overdekking vorm<strong>en</strong>. De par<strong>en</strong> α(ui) voor i = 1, . . . , 5 zijn dan<br />

{〈1, 1〉, 〈2, 2〉, 〈3, 2〉, 〈4, 1〉, 〈5, 1〉}<br />

De verzameling T bestaat uit de par<strong>en</strong>:<br />

{〈1, 1〉, 〈1, 2〉, 〈2, 2〉, 〈2, 4〉, 〈3, 2〉, 〈3, 3〉, 〈4, 1〉, 〈5, 1〉, 〈5, 3〉, 〈5, 4〉}<br />

<strong>en</strong> dus hebb<strong>en</strong> we de volg<strong>en</strong>de verzameling drietall<strong>en</strong>:<br />

<strong>en</strong> de drietall<strong>en</strong><br />

{(〈1, 1〉, 〈1, 1〉, 〈1, 1〉), (〈1, 1〉, 〈1, 2〉, 〈1, 2〉), (〈2, 2〉, 〈2, 2〉, 〈2, 2〉),<br />

(〈2, 2〉, 〈2, 4〉, 〈2, 4〉), (〈3, 2〉, 〈3, 2〉, 〈3, 2〉), (〈3, 2〉, 〈3, 3〉, 〈3, 3〉)<br />

(〈4, 1〉, 〈4, 1〉, 〈4, 1〉), (〈5, 1〉, 〈5, 1〉, 〈5, 1〉), (〈5, 1〉, 〈5, 3〉, 〈5, 3〉),<br />

(〈5, 1〉, 〈5, 4〉, 〈5, 4〉)}<br />

{(β, 〈1, 1〉, 〈4, 1〉), (β, 〈4, 1〉, 〈5, 1〉), (β, 〈5, 1〉, 〈1, 1〉),<br />

(β, 〈2, 2〉, 〈3, 2〉), (β, 〈3, 2〉, 〈2, 2〉), (β, 〈1, 3〉, 〈3, 3〉),<br />

(β, 〈3, 3〉, 〈5, 3〉), (β, 〈5, 3〉, 〈1, 3〉), (β, 〈2, 4〉, 〈5, 4〉),<br />

(β, 〈5, 4〉, 〈2, 4〉)}<br />

voor β lop<strong>en</strong>d over alle par<strong>en</strong> die niet α(i) zijn. E<strong>en</strong> overdekking <strong>van</strong> T × T × T is nu<br />

{(〈1, 1〉, 〈1, 1〉, 〈1, 1〉), (〈2, 2〉, 〈2, 2〉, 〈2, 2〉), (〈3, 2〉, 〈3, 2〉, 〈3, 2〉),<br />

(〈4, 1〉, 〈4, 1〉, 〈4, 1〉), (〈5, 1〉, 〈5, 1〉, 〈5, 1〉), (〈1, 2〉, 〈1, 3〉, 〈3, 3〉),<br />

(〈2, 4〉, 〈3, 3〉, 〈5, 3〉), (〈3, 3〉, 〈5, 3〉, 〈1, 3〉), (〈5, 3〉, 〈2, 4〉, 〈5, 4〉)<br />

(〈5, 4〉, 〈5, 4〉, 〈2, 4〉)}<br />

Het volg<strong>en</strong>de probleem in deze serie is KNAPSACK. We hebb<strong>en</strong> al eerder e<strong>en</strong> variant <strong>van</strong> KNAPSACK<br />

gezi<strong>en</strong> die kon word<strong>en</strong> opgelost met behulp <strong>van</strong> e<strong>en</strong> gulzige algoritme. Ook hebb<strong>en</strong> we gezi<strong>en</strong> dat dynamisch<br />

programmer<strong>en</strong> helpt om de discrete variant <strong>van</strong> KNAPSACK op te loss<strong>en</strong>. De gr<strong>en</strong>s die we vond<strong>en</strong> voor<br />

e<strong>en</strong> dynamisch programmer<strong>en</strong> algoritme voor e<strong>en</strong> KNAPSACK met n object<strong>en</strong> <strong>en</strong> gr<strong>en</strong>s b was n × b. We<br />

merk<strong>en</strong> op dat, hoewel deze algoritme voor begr<strong>en</strong>sde b e<strong>en</strong> polynomiale tijd algoritme is, de gevond<strong>en</strong> gr<strong>en</strong>s<br />

toch expon<strong>en</strong>tieel in de l<strong>en</strong>gte <strong>van</strong> de invoer kan zijn, omdat b nu e<strong>en</strong>maal in log b bits in de invoer kan<br />

word<strong>en</strong> gepres<strong>en</strong>teerd. Het bewijs dat KNAPSACK NP-volledig is, dat we hieronder gev<strong>en</strong>, is dan ook niet<br />

in teg<strong>en</strong>spraak met onze onwet<strong>en</strong>dheid omtr<strong>en</strong>t de relatie tuss<strong>en</strong> P <strong>en</strong> NP.<br />

naam: KNAPSACK<br />

gegev<strong>en</strong>: Gegev<strong>en</strong> e<strong>en</strong> verzameling gewicht<strong>en</strong> w1, . . . , wn <strong>en</strong> e<strong>en</strong> gr<strong>en</strong>s b<br />

gevraagd: Is er e<strong>en</strong> indexverzameling I zó dat �<br />

i∈I wi = b?<br />

Natuurlijk is KNAPSACK e<strong>en</strong> probleem in NP. Immers gegev<strong>en</strong> e<strong>en</strong> indexverzameling kunn<strong>en</strong> we gemakkelijk<br />

controler<strong>en</strong> dat de som <strong>van</strong> de gewicht<strong>en</strong> <strong>van</strong> de elem<strong>en</strong>t<strong>en</strong> in deze verzameling precies b is.<br />

KNAPSACK is echter ook NP-volledig. We lat<strong>en</strong> dit zi<strong>en</strong> door e<strong>en</strong> reductie <strong>van</strong> EXACT COVER. Laat e<strong>en</strong>s<br />

e<strong>en</strong> universum U = {1, . . . , n} gegev<strong>en</strong> zijn, <strong>en</strong> e<strong>en</strong> stel verzameling<strong>en</strong> Sj. We definier<strong>en</strong> uij = 1 ⇔ i ∈ Sj.<br />

Als we b = n kiez<strong>en</strong>, dan zi<strong>en</strong> we hier al dat wanneer er e<strong>en</strong> overdekking bestaat met de Sj die e<strong>en</strong> onderling<br />

lege doorsnede hebb<strong>en</strong>, de bijbehor<strong>en</strong>de uij precies tot n sommer<strong>en</strong>. We kunn<strong>en</strong> nu echter ook e<strong>en</strong> stel verzameling<strong>en</strong><br />

kiez<strong>en</strong> zodat de bijbehor<strong>en</strong>de uij tot n sommer<strong>en</strong> zonder dat deze verzameling<strong>en</strong> e<strong>en</strong> overdekking<br />

vorm<strong>en</strong>. We kunn<strong>en</strong> bijvoorbeeld n keer de verzameling {1} kiez<strong>en</strong>. De oplossing wordt gevond<strong>en</strong> door te<br />

verhinder<strong>en</strong> dat optelling<strong>en</strong> <strong>van</strong> elem<strong>en</strong>t<strong>en</strong> e<strong>en</strong> carry tot gevolg hebb<strong>en</strong>. Als het aantal deelverzameling<strong>en</strong> m<br />

is, dan kunn<strong>en</strong> we nooit meer dan m keer hetzelfde elem<strong>en</strong>t kiez<strong>en</strong>. In plaats <strong>van</strong> uij = 1 kiez<strong>en</strong> we uij = mi als i in Sj zit <strong>en</strong> 0 anders. Voor elke Sj mak<strong>en</strong> we nu het getal sj = �<br />

i uij <strong>en</strong> b = �n i=1 mi . Als er e<strong>en</strong> stel<br />

sj bestaat dat tot b sommeert, dan betek<strong>en</strong>t dat dat voor elke macht <strong>van</strong> m precies één j in dit stel is zo<br />

dat uij = m i , anders zi<strong>en</strong> we in de som m i niet met coëffici<strong>en</strong>t 1 optred<strong>en</strong>. Dus als er e<strong>en</strong> oplossing voor het<br />

KNAPSACK probleem is, dan is er ook e<strong>en</strong> exacte overdekking <strong>en</strong> omgekeerd.<br />

118<br />


Het laatste probleem in deze serie is boedelscheiding. Hier moet niet e<strong>en</strong> verzameling gevond<strong>en</strong> word<strong>en</strong><br />

die precies e<strong>en</strong> bepaald gewicht heeft, maar moet e<strong>en</strong> gegev<strong>en</strong> verzameling in tweeën gedeeld word<strong>en</strong> zodat<br />

beide del<strong>en</strong> precies ev<strong>en</strong>veel waarde hebb<strong>en</strong>. In de praktijk is de taak <strong>van</strong> de verdeler (rechter) natuurlijk<br />

om twee verzameling<strong>en</strong> te vind<strong>en</strong> die in waarde zo weinig mogelijk <strong>van</strong> elkaar verschill<strong>en</strong>, <strong>en</strong> wordt die keuze<br />

nog bemoeilijkt doordat hetzelfde object voor verschill<strong>en</strong>de person<strong>en</strong> verschill<strong>en</strong>de (emotionele) waarde kan<br />

hebb<strong>en</strong>, maar in onze ideale wereld <strong>van</strong> de wiskunde kunn<strong>en</strong> we dit probleem als beslissingsprobleem stell<strong>en</strong>,<br />

als volgt.<br />

naam: BOEDELSCHEIDING<br />

gegev<strong>en</strong>: Gegev<strong>en</strong> e<strong>en</strong> verzameling gewicht<strong>en</strong> w1, . . . , wn<br />

gevraagd: Is er e<strong>en</strong> indexverzameling I zó dat �<br />

i∈I wi = �<br />

i /∈I wi?<br />

Ook BOEDELSCHEIDING is e<strong>en</strong> probleem in NP. Immers, gegev<strong>en</strong> e<strong>en</strong> index verzameling kunn<strong>en</strong> we<br />

gemakkelijk controler<strong>en</strong> dat de beide deelverzameling gelijke som hebb<strong>en</strong>. BOEDELSCHEIDING is ook<br />

NP-volledig. Om dit te bewijz<strong>en</strong> gev<strong>en</strong> we e<strong>en</strong> reductie <strong>van</strong> KNAPSACK.<br />

Laat gegev<strong>en</strong> zijn e<strong>en</strong> stel gewicht<strong>en</strong> w1, . . . , wn <strong>en</strong> e<strong>en</strong> getal b. We mak<strong>en</strong> e<strong>en</strong> stel gewicht<strong>en</strong> w1, . . . , wn, wn+1, wn+2<br />

waarvoor e<strong>en</strong> boedelscheiding bestaat dan <strong>en</strong> slechts dan als de KNAPSACK e<strong>en</strong> oplossing heeft. De gewicht<strong>en</strong><br />

w1, . . . , wn blijv<strong>en</strong> gelijk. De nieuwe gewicht<strong>en</strong> wn+1 <strong>en</strong> wn+2 mak<strong>en</strong> we allereerst zo dat ze bij e<strong>en</strong><br />

boedelscheiding niet allebei aan dezelfde kant <strong>van</strong> de indexverzameling terecht kunn<strong>en</strong> kom<strong>en</strong>. Daarvoor<br />

mak<strong>en</strong> we wn+1 gelijk aan b + 1 <strong>en</strong> wn+2 gelijk aan � wi − b + 1. Als wn+1 <strong>en</strong> wn+2 nu allebei in I of juist<br />

niet in I zitt<strong>en</strong>, dan kunn<strong>en</strong> de overgeblev<strong>en</strong> elem<strong>en</strong>t<strong>en</strong> nooit e<strong>en</strong> zo grote som hebb<strong>en</strong> dat dit kan word<strong>en</strong><br />

gecomp<strong>en</strong>seerd.<br />

Veronderstel nu dat er e<strong>en</strong> boedelscheiding mogelijk is. Dus dat er e<strong>en</strong> indexverzameling I bestaat, zodat<br />

.<br />

Dan is 2 �<br />

i∈I wi = 2b, ofwel �<br />

i∈I wi = b<br />

Kleur<strong>en</strong><br />

wn+2 + �<br />

k∈I wk =<br />

�<br />

i≤n wi − b + 1 + �<br />

k∈I wk =<br />

b + 1 + �<br />

ℓ /∈I wℓ =<br />

wn+1 + �<br />

ℓ /∈I wℓ<br />

De laatste familie <strong>van</strong> problem<strong>en</strong> die we in deze tekst besprek<strong>en</strong> is de familie <strong>van</strong> de kleur<strong>en</strong>problem<strong>en</strong>. Het<br />

beroemdste lid <strong>van</strong> deze familie is misschi<strong>en</strong> wel het vierkleur<strong>en</strong>probleem voor planaire graf<strong>en</strong>. Gegev<strong>en</strong> is<br />

e<strong>en</strong> landkaart met land<strong>en</strong> die niet in één punt aan elkaar gr<strong>en</strong>z<strong>en</strong>. Gevraagd is de landkaart met vier kleur<strong>en</strong><br />

in te kleur<strong>en</strong>. Verrass<strong>en</strong>d g<strong>en</strong>oeg lukt dit altijd. Pas in de vorige eeuw werd bewez<strong>en</strong> door Appel <strong>en</strong> Hak<strong>en</strong><br />

dat e<strong>en</strong> planaire graaf (dat is e<strong>en</strong> graaf die in het platte vlak kan word<strong>en</strong> ingebed) met vier kleur<strong>en</strong> altijd zo<br />

kan word<strong>en</strong> gekleurd dat ge<strong>en</strong> twee knop<strong>en</strong> die aan dezelfde kant zitt<strong>en</strong> dezelfde kleur krijg<strong>en</strong>. Dit noem<strong>en</strong><br />

we e<strong>en</strong> legale kleuring. Het bewijs reduceerde eerst de oneindige verzameling <strong>van</strong> planaire graf<strong>en</strong> tot e<strong>en</strong><br />

eindig aantal typ<strong>en</strong> (e<strong>en</strong> paar duiz<strong>en</strong>d) waar<strong>van</strong> vervolg<strong>en</strong>s met behulp <strong>van</strong> e<strong>en</strong> computerprogramma kon<br />

word<strong>en</strong> aangetoond dat ze allemaal vierkleurbaar zijn. E<strong>en</strong> inzichtelijk bewijs voor deze stelling ontbreekt<br />

echter altijd nog.<br />

Voor planaire graf<strong>en</strong> <strong>en</strong> K ≥ 4 is het probleem ” kan de graaf met K kleur<strong>en</strong> word<strong>en</strong> gekleurd” dus e<strong>en</strong><br />

simpel probleem. Het antwoord is ja. Voor algem<strong>en</strong>e graf<strong>en</strong>, <strong>en</strong> ook voor K = 3 is het probleem NP-volledig,<br />

zoals we hieronder kunn<strong>en</strong> zi<strong>en</strong>. Voor K = 2 is het probleem opnieuw simpel, hoewel dan voor sommige<br />

graf<strong>en</strong> het antwoord ja <strong>en</strong> voor andere het antwoord nee is.<br />

Het graf<strong>en</strong>kleurprobleem: ” met hoeveel kleur<strong>en</strong> kan e<strong>en</strong> graaf word<strong>en</strong> gekleurd?” is e<strong>en</strong> uitbreiding <strong>van</strong><br />

het onafhankelijke verzameling probleem. Immers e<strong>en</strong> graaf moet word<strong>en</strong> onderverdeeld in e<strong>en</strong> aantal onafhankleijke<br />

verzameling<strong>en</strong>, <strong>en</strong> wat is het minimale aantal waarvoor dit mogelijk is? Het probleem wordt<br />

CHROMATIC NUMBER g<strong>en</strong>oemd in Engelse tekst<strong>en</strong>. Hier zull<strong>en</strong> wij het aanduid<strong>en</strong> met het KLEURGE-<br />

TAL <strong>van</strong> e<strong>en</strong> graaf.<br />

naam: KLEURGETAL<br />

119


• •<br />

• •<br />

• • •<br />

• •<br />

Figuur 6.8: Gadget voor 3-Kleurbaarheid<br />

gegev<strong>en</strong>: Gegev<strong>en</strong> e<strong>en</strong> graaf G <strong>en</strong> e<strong>en</strong> getal K<br />

gevraagd: Is er e<strong>en</strong> legale kleuring <strong>van</strong> G met K kleur<strong>en</strong>?<br />

Ook dit is e<strong>en</strong> probleem in NP, want gegev<strong>en</strong> e<strong>en</strong> oplossing kunn<strong>en</strong> we gemakkelijk controler<strong>en</strong> dat de<br />

regels <strong>van</strong> kleurbaarheid niet overschred<strong>en</strong> zijn <strong>en</strong> dat slechts K kleur<strong>en</strong> gebruikt zijn. Om aan te ton<strong>en</strong> dat<br />

het probleem ook NP-volledig is gev<strong>en</strong> we e<strong>en</strong> reductie <strong>van</strong> 3SAT.<br />

Gegev<strong>en</strong> is dus e<strong>en</strong> formule F (x1, . . . , xn), <strong>en</strong> we gaan e<strong>en</strong> graaf mak<strong>en</strong> die met n + 1 kleur<strong>en</strong> te kleur<strong>en</strong><br />

is dan <strong>en</strong> slechts dan als de formule vervulbaar is. We nem<strong>en</strong> zonder beperking der algeme<strong>en</strong>heid aan dat<br />

n ≥ 4. Allereerst mak<strong>en</strong> we e<strong>en</strong> complete graaf op n knop<strong>en</strong>, B, die ervoor zorgt dat de meeste kleur<strong>en</strong><br />

vergev<strong>en</strong> zijn. Om deze graaf te kleur<strong>en</strong> hebb<strong>en</strong> we t<strong>en</strong>minste n kleur<strong>en</strong> nodig. Vervolg<strong>en</strong>s voer<strong>en</strong> we 2n<br />

knop<strong>en</strong> xi <strong>en</strong> xi in die we paarsgewijs met elkaar verbind<strong>en</strong>, zodat ze niet dezelfde kleur kunn<strong>en</strong> krijg<strong>en</strong>.<br />

Deze knop<strong>en</strong> stell<strong>en</strong> de variabel<strong>en</strong> voor. Bov<strong>en</strong>di<strong>en</strong> word<strong>en</strong> de knop<strong>en</strong> uit elk paar met alle knop<strong>en</strong> behalve<br />

1 uit B verbond<strong>en</strong>. Hoogst<strong>en</strong>s één <strong>van</strong> deze knop<strong>en</strong> kan dus de kleur <strong>van</strong> deze <strong>en</strong>e knoop uit B krijg<strong>en</strong>. De<br />

andere knoop moet de <strong>en</strong>ig overgeblev<strong>en</strong> n + 1e kleur krijg<strong>en</strong>, deze kleur zal de kleur “onwaar” voorstell<strong>en</strong>.<br />

We voer<strong>en</strong> m knop<strong>en</strong> cj in. Deze knop<strong>en</strong> stell<strong>en</strong> de zinn<strong>en</strong> voor. T<strong>en</strong>slotte zull<strong>en</strong> cj verbond<strong>en</strong> zijn met xi<br />

(xi) als xi (xi) niet in de zin cj voorkomt.<br />

We bewer<strong>en</strong> nu dat de aldus geconstrueerde graaf gekleurd kan word<strong>en</strong> met n + 1 kleur<strong>en</strong> dan <strong>en</strong> slechts<br />

dan als F vervulbaar is. Lat<strong>en</strong> we eerst e<strong>en</strong>s kijk<strong>en</strong> hoe deze graaf gekleurd zou kunn<strong>en</strong> word<strong>en</strong>. We hadd<strong>en</strong><br />

al gezi<strong>en</strong> dat er n kleur<strong>en</strong> voor de deelgraaf B nodig zijn. Van de par<strong>en</strong> xi, xi is er één die de n + 1e kleur<br />

moet krijg<strong>en</strong>. Alle andere moet<strong>en</strong> één <strong>van</strong> de n eerste kleur<strong>en</strong> krijg<strong>en</strong>. Verder kan ge<strong>en</strong> <strong>van</strong> xi, xi, xj, xj<br />

dezelfde kleur kan krijg<strong>en</strong> voor i �= j. Omdat n ≥ 4, is elke knoop cj wel verbond<strong>en</strong> met zowel xi als xi voor<br />

één of andere i. Dus cj kan niet met kleur n + 1 gekleurd word<strong>en</strong>. In e<strong>en</strong> legale kleuring kan cj dus alle<strong>en</strong><br />

de kleur <strong>van</strong> e<strong>en</strong> xi of e<strong>en</strong> xi krijg<strong>en</strong> die wel in de jde zin voorkomt <strong>en</strong> die niet de n + 1e kleur (onwaar)<br />

gekreg<strong>en</strong> heeft. Dat betek<strong>en</strong>t dus dat als de graaf gekleurd kan word<strong>en</strong>, we in elke zin e<strong>en</strong> xi of xi kunn<strong>en</strong><br />

kiez<strong>en</strong> die waargemaakt kan word<strong>en</strong> <strong>en</strong> dus dat F waargemaakt kan word<strong>en</strong>. Dit recept, in omgekeerde<br />

vorm, geeft tev<strong>en</strong>s bij iedere toewijzing die F waarmaakt e<strong>en</strong> kleuring <strong>van</strong> de graaf.<br />

naam: 3-KLEURBAARHEID<br />

gegev<strong>en</strong>: Gegev<strong>en</strong> e<strong>en</strong> graaf G<br />

gevraagd: Is er e<strong>en</strong> legale 3-kleuring <strong>van</strong> G?<br />

Als het algem<strong>en</strong>e kleuringsprobleem e<strong>en</strong> probleem in NP is, geldt dat natuurlijk ook voor het probleem<br />

als we het aantal kleur<strong>en</strong> tot drie beperk<strong>en</strong>. Wat opmerkelijker is, is dat deze beperking het probleem niet<br />

makkelijker maakt. Om dit te bewijz<strong>en</strong> gev<strong>en</strong> we weer e<strong>en</strong> reductie <strong>van</strong> 3SAT. In dit geval hebb<strong>en</strong> we, zoals<br />

in het geval <strong>van</strong> de reductie <strong>van</strong> VERTEX COVER naar HAMILTON CIRCUIT kleine graafjes nodig met<br />

e<strong>en</strong> bijzondere eig<strong>en</strong>schap, zog<strong>en</strong>oemde gadgets. Hier mak<strong>en</strong> we gebruik <strong>van</strong> de graafjes uit Figuur 6.8<br />

Gegev<strong>en</strong> drie kleur<strong>en</strong>, bijvoorbeeld r, b <strong>en</strong> z heeft deze graaf de eig<strong>en</strong>schap dat als alle drie de knop<strong>en</strong><br />

aan de linkerkant dezelfde kleur krijg<strong>en</strong>, bijvoorbeeld z, dan wordt de meest rechtse knoop ook met deze<br />

kleur gekleurd. Dit is e<strong>en</strong> mooie karakterizatie voor 3-SAT. Als namelijk alle optred<strong>en</strong>s <strong>van</strong> variabel<strong>en</strong> in<br />

e<strong>en</strong> zin <strong>van</strong> 3-SAT de waarde onwaar krijg<strong>en</strong>, dan krijgt de zin ook deze waarde. Nu voer<strong>en</strong> we voor elke<br />

variabele xi twee knop<strong>en</strong> xi, <strong>en</strong> xi in, die we met elkaar verbind<strong>en</strong>, zodat ze niet dezelfde kleur kunn<strong>en</strong><br />

120


•<br />

• • •<br />

• • • • •<br />

• • •<br />

•<br />

Figuur 6.9: Crossover Compon<strong>en</strong>t<br />

krijg<strong>en</strong> <strong>en</strong> we verbind<strong>en</strong> al deze knop<strong>en</strong> met e<strong>en</strong> derde knoop R, zodat er maar twee kleur<strong>en</strong> overblijv<strong>en</strong> om<br />

xi <strong>en</strong> xi te kleur<strong>en</strong>. Voor elke zin in de formule nem<strong>en</strong> we e<strong>en</strong> graafje zoals in Figuur 6.8, <strong>en</strong> we verbind<strong>en</strong><br />

alle rechterknop<strong>en</strong> <strong>van</strong> deze figuurtjes met R zodat de rechterkant<strong>en</strong> één <strong>van</strong> de twee kleur<strong>en</strong> moet<strong>en</strong> krijg<strong>en</strong><br />

die we voor xi <strong>en</strong> xi gebruik<strong>en</strong>. We verbind<strong>en</strong> alle rechterkant<strong>en</strong> nog met e<strong>en</strong> extra knoop F die zelf met<br />

R verbond<strong>en</strong> is, zodat er nog maar één kleur voor de rechterkant<strong>en</strong> overblijft. Nu krijg<strong>en</strong> alle linkerkant<strong>en</strong><br />

<strong>van</strong> de figuurtjes de naam <strong>van</strong> het optred<strong>en</strong> <strong>van</strong> de variabele op die plaats in die zin (dus xi of xj) <strong>en</strong> we<br />

smelt<strong>en</strong> alle knop<strong>en</strong> die dezelfde naam hebb<strong>en</strong> tot één knoop.<br />

Als nu de resulter<strong>en</strong>de graaf gekleurd kan word<strong>en</strong>, dan hebb<strong>en</strong> alle rechterkant<strong>en</strong> <strong>van</strong> de figuurtjes dezelfde<br />

kleur, <strong>en</strong> deze kleur komt op minst<strong>en</strong>s één plaats aan de linkerkant voor. Dat betek<strong>en</strong>t, als we deze kleur<br />

ev<strong>en</strong> waar noem<strong>en</strong>, dat in elke zin e<strong>en</strong> optred<strong>en</strong> <strong>van</strong> e<strong>en</strong> variabele gekoz<strong>en</strong> kan word<strong>en</strong> die waargemaakt<br />

kan word<strong>en</strong>, <strong>en</strong> dat betek<strong>en</strong>t weer dat F waargemaakt kan word<strong>en</strong>. Omgekeerd geeft e<strong>en</strong> toewijzing <strong>van</strong><br />

waarheidswaard<strong>en</strong> die F waarmaakt met dit recept e<strong>en</strong> legale driekleuring <strong>van</strong> de graaf.<br />

naam: PLANAIRE 3-KLEURBAARHEID<br />

gegev<strong>en</strong>: Gegev<strong>en</strong> e<strong>en</strong> planaire graaf G<br />

gevraagd: Is er e<strong>en</strong> legale 3-kleuring <strong>van</strong> G?<br />

We hebb<strong>en</strong> e<strong>en</strong> nog specialer geval <strong>van</strong> e<strong>en</strong> probleem in NP dus ook dit probleem is e<strong>en</strong> probleem in NP.<br />

E<strong>en</strong> gegev<strong>en</strong> oplossing kan gemakkelijk gecontroleerd word<strong>en</strong>. Zelfs planariteit maakt echter het probleem<br />

niet makkelijker als het aantal kleur<strong>en</strong> beperkt wordt tot drie. Om dit te bewijz<strong>en</strong> lat<strong>en</strong> we zi<strong>en</strong> dat we<br />

elk paar kant<strong>en</strong> die de graaf niet planair mak<strong>en</strong>, omdat ze niet in twee dim<strong>en</strong>sies kunn<strong>en</strong> word<strong>en</strong> ingebed,<br />

kunn<strong>en</strong> word<strong>en</strong> ver<strong>van</strong>g<strong>en</strong> door e<strong>en</strong> compon<strong>en</strong>t die wel planair is, zo dat de uiteind<strong>en</strong> <strong>van</strong> die compon<strong>en</strong>t de<br />

kleur ” bewar<strong>en</strong>”. We mak<strong>en</strong> e<strong>en</strong> graaf die de eig<strong>en</strong>schap heeft dat hij planair <strong>en</strong> driekleurbaar is <strong>en</strong> dat de<br />

kleur <strong>van</strong> de meest linker knoop dezelfde moet zijn als de kleur <strong>van</strong> de meest rechter knoop <strong>en</strong> dat de kleur<br />

<strong>van</strong> de bov<strong>en</strong>ste knoop dezelfde moet zijn als de kleur <strong>van</strong> de onderste knoop. Deze graaf wordt gegev<strong>en</strong> in<br />

Figuur 6.9. Als we e<strong>en</strong> niet planaire graaf hebb<strong>en</strong>, dan kunn<strong>en</strong> we de par<strong>en</strong> kant<strong>en</strong> die in drie dim<strong>en</strong>sies<br />

kruis<strong>en</strong> paar voor paar ver<strong>van</strong>g<strong>en</strong> door zo’n crossover compon<strong>en</strong>t <strong>en</strong> we houd<strong>en</strong> e<strong>en</strong> platte graaf over. Elke<br />

driekleuring <strong>van</strong> de oorspronkelijke graaf geeft e<strong>en</strong> driekleuring <strong>van</strong> de nieuwe graaf <strong>en</strong> omgekeerd, <strong>van</strong>wege<br />

de eig<strong>en</strong>schap <strong>van</strong> deze crossover compon<strong>en</strong>t<strong>en</strong>.<br />

6.5.2 Besliss<strong>en</strong>, Optimalisatie <strong>en</strong> Zelfreduceerbaarheid<br />

NP-volledige problem<strong>en</strong> zoals we in hierbov<strong>en</strong> hebb<strong>en</strong> gezi<strong>en</strong> kom<strong>en</strong> in de praktijk vaak voor als optimaliseringsproblem<strong>en</strong>.<br />

Er wordt niet gevraagd: ” is er e<strong>en</strong> overdekking waarbij de paarsgewijze doorsned<strong>en</strong><br />

leeg zijn?”, maar: ” wat is de overdekking waarbij het totale aantal vaker voorkom<strong>en</strong>de elem<strong>en</strong>t<strong>en</strong> zo klein<br />

mogelijk is?” Niet: ” is er e<strong>en</strong> boedelscheiding waarbij de <strong>en</strong>e verzameling precies ev<strong>en</strong>veel waard is als de<br />

121


andere?”, maar: ” bij welke boedelscheiding is het verschil zo klein mogelijk?”, etc. etc. Ook will<strong>en</strong> we graag<br />

<strong>van</strong> e<strong>en</strong> algoritme die e<strong>en</strong> antwoord op ons probleem geeft graag wat meer informatie dan alle<strong>en</strong> maar ja/nee.<br />

Als we e<strong>en</strong> algoritme hebb<strong>en</strong> die beslist of e<strong>en</strong> graaf op 500 knop<strong>en</strong> 32 kleurbaar is, dan is ” ja” misschi<strong>en</strong><br />

niet e<strong>en</strong> antwoord waar we erg gelukkig <strong>van</strong> word<strong>en</strong>. We will<strong>en</strong> zo’n kleuring ook graag in hand<strong>en</strong> hebb<strong>en</strong>.<br />

Tuss<strong>en</strong> besliss<strong>en</strong> <strong>en</strong> optimaliser<strong>en</strong> is gelukkig e<strong>en</strong> e<strong>en</strong>voudig verband. E<strong>en</strong> snelle beslissingsalgoritme geeft<br />

e<strong>en</strong> snelle optimaliseringsalgoritme door tuss<strong>en</strong>komst <strong>van</strong> binair zoek<strong>en</strong>, <strong>en</strong> e<strong>en</strong> snelle optimaliseringsalgoritme<br />

geeft triviaal e<strong>en</strong> snelle beslissingsalgoritme. Toch valt er nog iets meer over te zegg<strong>en</strong>. E<strong>en</strong> algoritme<br />

voor het besliss<strong>en</strong> <strong>van</strong> VERTEX COVER geeft voor de par<strong>en</strong> G, k, waarbij G e<strong>en</strong> graaf is <strong>en</strong> k e<strong>en</strong> aantal<br />

knop<strong>en</strong> het antwoord “ja” als er e<strong>en</strong> vertex cover <strong>van</strong> grootte hoogst<strong>en</strong>s k in de graaf zit. Voor zo’n vertex<br />

cover bestaat e<strong>en</strong> kort bewijs, bijvoorbeeld zo’n verzameling knop<strong>en</strong>. Het is echter helemaal niet duidelijk<br />

wat e<strong>en</strong> kort bewijs zou zijn voor de uitspraak G heeft ge<strong>en</strong> vertex cover <strong>van</strong> grootte k. Het complem<strong>en</strong>t <strong>van</strong><br />

het probleem VERTEX COVER bestaant uit alle par<strong>en</strong> G, k waarvoor de kleinste vertex cover in G groter<br />

is dan k. Dit zou dus wel e<strong>en</strong>s wez<strong>en</strong>lijk moeilijker kunn<strong>en</strong> zijn dan VERTEX COVER zelf. Uiteraard is<br />

niet het geval wanneer er e<strong>en</strong> deterministisch polynomiale tijd algoritme voor VERTEX COVER zou zijn.<br />

Problem<strong>en</strong> die <strong>van</strong> de vorm zijn als in dit voorbeeld—de kleinste vertex cover in G heeft grootte k—vorm<strong>en</strong><br />

e<strong>en</strong> aparte klasse. Ze kunn<strong>en</strong> word<strong>en</strong> opgelost door e<strong>en</strong> deterministisch polynomiale tijd machine die toegang<br />

heeft tot vrag<strong>en</strong> aan NP-volledige problem<strong>en</strong>. Deze klasse wordt ∆ P 2 g<strong>en</strong>oemd. Ook ∆ P 2 heeft volledige<br />

problem<strong>en</strong>. E<strong>en</strong> bek<strong>en</strong>d voorbeeld is ODDMINSAT, ” de lexicografisch kleinste vervulling <strong>van</strong> e<strong>en</strong> formule is<br />

onev<strong>en</strong>”.<br />

Als we e<strong>en</strong> algoritme voor e<strong>en</strong> beslissingsprobleem hebb<strong>en</strong>, dan will<strong>en</strong> we ook wel graag e<strong>en</strong> oplossing<br />

in hand<strong>en</strong> hebb<strong>en</strong> (dit wordt het ” witness probleem” g<strong>en</strong>oemd). Ook hier is er bij de meeste NP-volledige<br />

problem<strong>en</strong> e<strong>en</strong> e<strong>en</strong>voudig verband aan te gev<strong>en</strong>. De meeste NP-volledige problem<strong>en</strong> zijn zelfreduceerbaar,<br />

dwz. terug te voer<strong>en</strong> op kleinere instanties <strong>van</strong> zichzelf. Uit zo’n zelfreductie kunn<strong>en</strong> we e<strong>en</strong> algoritme bouw<strong>en</strong><br />

die ons e<strong>en</strong> oplossing in hand<strong>en</strong> geeft. We gev<strong>en</strong> e<strong>en</strong> paar voorbeeld<strong>en</strong>.<br />

1. SATISFIABILITY. Stel we hebb<strong>en</strong> e<strong>en</strong> algoritme die e<strong>en</strong> antwoord kan gev<strong>en</strong> op de vraag of e<strong>en</strong><br />

formule F (x1, x2, . . . , xn) vervulbaar is. F is alle<strong>en</strong> vervulbaar als F (0, x2, . . . , xn) vervulbaar is of<br />

F (1, x2, . . . , xn) vervulbaar is. E<strong>en</strong> hypothetische beslissingsalgoritme voor SATISFIABILITY kan nu<br />

recursief gebruikt word<strong>en</strong> om e<strong>en</strong> vervulling te vind<strong>en</strong> door de vervulbaarheid <strong>van</strong> F (1, x2, . . . , xn) <strong>en</strong>/of<br />

F (0, x2, . . . , xn) te besliss<strong>en</strong> <strong>en</strong> het antwoord hierop te gebruik<strong>en</strong> voor verdere recursieve aanroep<strong>en</strong>.<br />

De onderstaande algoritme vindt e<strong>en</strong> vervulling voor e<strong>en</strong> vervulbare formule F (x1, . . . , xn). Om de<br />

notatie e<strong>en</strong>voudiger te mak<strong>en</strong> nem<strong>en</strong> we aan dat we in F e<strong>en</strong> bitstring s kunn<strong>en</strong> invull<strong>en</strong>, <strong>en</strong> dat F (s)<br />

betek<strong>en</strong>t F met xi gelijk aan het ide bit <strong>van</strong> s. Verder is s0 de bitstring s met aan het einde e<strong>en</strong><br />

0 geplakt <strong>en</strong> s1 de bitstring s met aan het einde e<strong>en</strong> 1 geplakt. De aanroep SAT(F, ∅); Het diepste<br />

niveau <strong>van</strong> de recursie drukt e<strong>en</strong> bitstring <strong>van</strong> l<strong>en</strong>gte n af die e<strong>en</strong> vervulling voorstelt.<br />

1: function SAT(F , s)<br />

2: if |s| < n th<strong>en</strong><br />

3: if F (s0) ∈ SAT th<strong>en</strong><br />

4: SAT(F ,s0);<br />

5: else<br />

6: SAT(F ,s1);<br />

7: <strong>en</strong>d if<br />

8: else<br />

9: print(s);<br />

10: <strong>en</strong>d if<br />

2. VERTEX COVER. Bij dit probleem merk<strong>en</strong> we op dat <strong>van</strong> elk tweetal punt<strong>en</strong> dat door e<strong>en</strong> kant<br />

verbond<strong>en</strong> wordt, t<strong>en</strong>minste één in e<strong>en</strong> VERTEX COVER zit. De recursieve aanroep <strong>van</strong> de procedure<br />

kiest dus één <strong>van</strong> die punt<strong>en</strong> <strong>en</strong> vraagt of de graaf zonder dat punt e<strong>en</strong> VERTEX COVER heeft die<br />

één punt minder bevat. In de onderstaande algoritme is G − {v} de graaf G waaruit het punt v <strong>en</strong><br />

alle kant<strong>en</strong> die v als eindpunt hebb<strong>en</strong> verwijderd zijn. De algoritme vindt dan e<strong>en</strong> verzameling <strong>van</strong><br />

k punt<strong>en</strong> die e<strong>en</strong> vertex cover <strong>van</strong> G zijn, als we beginn<strong>en</strong> met e<strong>en</strong> G die inderdaad zo’n VERTEX<br />

COVER heeft.<br />

122


1: procedure VC(G, k)<br />

2: if G has edges th<strong>en</strong><br />

3: Choose an edge (v, w) in G;<br />

4: if (G − {v}, k − 1) ∈ VERTEXCOVER th<strong>en</strong><br />

5: print(v); VC(G − {v}, k − 1);<br />

6: elseprint(w); VC(G − {w}, k − 1);<br />

7: <strong>en</strong>d if<br />

8: <strong>en</strong>d if<br />

3. HAMILTON CIRCUIT. Stel we kiez<strong>en</strong> e<strong>en</strong> kant e in G. Ofwel de graaf G − {e} heeft nog steeds e<strong>en</strong><br />

Hamilton circuit ofwel G−{e} heeft ge<strong>en</strong> Hamilton circuit meer. In het tweede geval (aang<strong>en</strong>om<strong>en</strong> dat<br />

G zelf wel e<strong>en</strong> Hamilton circuit heeft, is e e<strong>en</strong> kant in elk Hamilton circuit <strong>en</strong> heeft G/{e}—de graaf<br />

die ontstaat als we beide einpunt<strong>en</strong> <strong>van</strong> e sam<strong>en</strong>trekk<strong>en</strong> tot één punt—weer wel e<strong>en</strong> Hamilton circuit.<br />

Deze algoritme kunn<strong>en</strong> we gebruik<strong>en</strong> totdat e<strong>en</strong> graaf overblijft die klein g<strong>en</strong>oeg is om het overgeblev<strong>en</strong><br />

Hamilton circuit te id<strong>en</strong>tificer<strong>en</strong> (bijvoorbeeld als G tot e<strong>en</strong> driehoek gereduceerd is).<br />

1: procedure HAM(G);<br />

2: if G is bigger than a triangle th<strong>en</strong><br />

3: Choose e in G<br />

4: if G − {e} ∈ HAMILTONCIRCUIT th<strong>en</strong><br />

5: HAM(G − {e});<br />

6: else<br />

7: print(e);<br />

8: HAM(G/{e})<br />

9: <strong>en</strong>d if<br />

10: else<br />

11: print(the edges in G);<br />

12: <strong>en</strong>d if<br />

Op deze wijze kunn<strong>en</strong> we voor vrijwel alle besprok<strong>en</strong> problem<strong>en</strong> e<strong>en</strong> recursieve algoritme vind<strong>en</strong> die e<strong>en</strong><br />

certificaat produceert voor e<strong>en</strong> instantie die tot het probleem behoort. In deze recursieve algoritm<strong>en</strong> wordt<br />

echter telk<strong>en</strong>s in e<strong>en</strong> if statem<strong>en</strong>t het oploss<strong>en</strong> <strong>van</strong> e<strong>en</strong> NP-volledig probleem gevraagd. Omdat echter e<strong>en</strong><br />

certificaat wordt geproduceerd, kan deze if zelf echter weer ver<strong>van</strong>g<strong>en</strong> word<strong>en</strong> door e<strong>en</strong> recursieve aanroep,<br />

waardoor e<strong>en</strong> recursieve algoritme voor het beslissingsprobleem zelf ontstaat. We nem<strong>en</strong> als voorbeeld<br />

VERTEX COVER. Nu is de aanroep VC(G, k) <strong>en</strong> de functie VC geeft nu 0 of 1 terug als de ingevoerde graaf<br />

ge<strong>en</strong>, resp. wel e<strong>en</strong> Vertex Cover <strong>van</strong> grootte k heeft.<br />

1: function VC(G = (V, E), k)<br />

2: if th<strong>en</strong>k ≥ |E | return(1)<br />

3: <strong>en</strong>d if<br />

4: if th<strong>en</strong>|E | > 0<br />

5: Choose edge (v, w) in G<br />

6: if VC(G − {v}, k − 1) th<strong>en</strong><br />

7: return(1);<br />

8: else if VC(G − {w}, k − 1) th<strong>en</strong><br />

9: return(1);<br />

10: else<br />

11: return(0);<br />

12: <strong>en</strong>d if<br />

13: <strong>en</strong>d if<br />

E<strong>en</strong> aldus verkreg<strong>en</strong> recursieve algoritme voor e<strong>en</strong> NP-volledig probleem moet altijd t<strong>en</strong>minste twee<br />

recursieve aanroep<strong>en</strong> hebb<strong>en</strong>, omdat anders het probleem in P terecht zou kom<strong>en</strong> <strong>en</strong> we e<strong>en</strong> P=NP bewijs<br />

hebb<strong>en</strong>. In sommige gevall<strong>en</strong>, zoals bijvoorbeeld in het geval <strong>van</strong> Traveling Sales Person zi<strong>en</strong> we zelfs meer<br />

dan één recursieve aanroep. De meeste bek<strong>en</strong>de NP-volledige problem<strong>en</strong> lat<strong>en</strong> op deze wijze e<strong>en</strong> recursieve<br />

123


algoritme toe. De recursieve aanroep<strong>en</strong> zijn disjuncties. Als één <strong>van</strong> de recursieve aanroep<strong>en</strong> slaagt is het<br />

antwoord ” ja”. Bov<strong>en</strong>di<strong>en</strong> kan het aantal aanroep<strong>en</strong> vaak tot twee (maar niet tot minder) beperkt word<strong>en</strong>.<br />

We noem<strong>en</strong> deze speciale vorm <strong>van</strong> zelfreduceerbaarheid twee-disjunctieve zelfreduceerbaarheid. Het is helaas<br />

onbek<strong>en</strong>d of misschi<strong>en</strong> alle NP-volledige problem<strong>en</strong> zelfreduceerbaar zijn. Omgekeerd is het wel bek<strong>en</strong>d dat<br />

alle zelfreduceerbare problem<strong>en</strong> in de grotere complexiteitsklasse PSPACE zitt<strong>en</strong>.<br />

6.6 Somm<strong>en</strong><br />

1. Bewijs dat er deterministisch polynomiale tijd begr<strong>en</strong>sde algoritm<strong>en</strong> bestaan voor<br />

(a) 2-SAT. SATISFIABILITY <strong>van</strong> proposities in conjunctieve normaalvorm met hoogst<strong>en</strong>s twee optred<strong>en</strong>s<br />

<strong>van</strong> variabel<strong>en</strong> per conjunctie.<br />

(b) Graph 2-colorability. Is het mogelijk e<strong>en</strong> graaf te kleur<strong>en</strong> met slechts twee verschill<strong>en</strong>de kleur<strong>en</strong>.<br />

2. Bewijs de NP-volledigheid <strong>van</strong> de volg<strong>en</strong>de problem<strong>en</strong>:<br />

(a) naam: DUAL-SATISFIABILITY<br />

gegev<strong>en</strong>: E<strong>en</strong> formule F (x1, . . . , xn)<br />

gevraagd: Zijn er minst<strong>en</strong>s twee verschill<strong>en</strong>de toewijzing<strong>en</strong> aan x1, . . . , xn die F waar mak<strong>en</strong>?<br />

(b) naam: DUAL-VERTEX COVER<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G = (V, E) <strong>en</strong> e<strong>en</strong> getal k<br />

gevraagd: Zijn er t<strong>en</strong>minste twee verschil<strong>en</strong>de verzameling<strong>en</strong> V ′ ⊆ V met |V ′ | ≤ k die allebei<br />

e<strong>en</strong> vertex cover <strong>van</strong> G zijn?<br />

(c) naam: HITTING SET<br />

gegev<strong>en</strong>: E<strong>en</strong> stel verzameling<strong>en</strong> getall<strong>en</strong> Si ⊆ V <strong>en</strong> e<strong>en</strong> getal k.<br />

gevraagd: Is er e<strong>en</strong> deelverzameling V ′ ⊆ V met |V | ≤ k <strong>en</strong> |V ′ ∩ Si | ≥ 1 voor alle i?<br />

(d) naam: FEEDBACK VERTEX SET<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G = (V, E) <strong>en</strong> e<strong>en</strong> getal k.<br />

gevraagd: Is er e<strong>en</strong> deelverzameling V ′ ⊆ V met |V ′ | ≤ k zo dat elke cykel <strong>van</strong> G t<strong>en</strong>minste<br />

één knoop <strong>van</strong> V ′ raakt?<br />

(e) naam: XXX<br />

gegev<strong>en</strong>: E<strong>en</strong> collectie deelverzameling<strong>en</strong> {Sj}j <strong>van</strong> U = {1, . . . , n} <strong>en</strong> twee getall<strong>en</strong> k <strong>en</strong> ℓ<br />

gevraagd: Bestaat er e<strong>en</strong> deelverzameling S = {ui1 , . . . , uik } zó dat voor ℓ verschill<strong>en</strong>de j’s<br />

geldt Sj ⊆ S?<br />

(f) naam: YYY<br />

gegev<strong>en</strong>: E<strong>en</strong> collectie deelverzameling<strong>en</strong> {Sj}j <strong>van</strong> U = {1, . . . , n} <strong>en</strong> twee getall<strong>en</strong> k <strong>en</strong> ℓ<br />

gevraagd: Bestaat er e<strong>en</strong> deelverzameling S = {ui1, . . . , uik } zó dat alle j’s geldt |Sj ∩ S | ≤ 1?<br />

3. Van de onderstaande problem<strong>en</strong> zijn er drie in P <strong>en</strong> is er één NP-volledig. Welke zijn dit?<br />

(a) Gegev<strong>en</strong> e<strong>en</strong> graaf G bestaat er e<strong>en</strong> onafhankelijke verzameling <strong>van</strong> grootte 3?<br />

(b) Gegev<strong>en</strong> e<strong>en</strong> gerichte gewog<strong>en</strong> volledige graaf K = (V, A) <strong>en</strong> e<strong>en</strong> getal k, is de som <strong>van</strong> de gewicht<strong>en</strong><br />

der kant<strong>en</strong> in elk Hamilton circuit groter dan k?<br />

(c) Gegev<strong>en</strong> e<strong>en</strong> ongerichte graaf G = (V, E); bestaat er e<strong>en</strong> V ′ ⊂ V , zó dat alle kant<strong>en</strong> uit E incid<strong>en</strong>t<br />

zijn met e<strong>en</strong> knoop uit V ′ ?<br />

(d) Gegev<strong>en</strong> e<strong>en</strong> zoekboom hor<strong>en</strong>de bij e<strong>en</strong> indep<strong>en</strong>d<strong>en</strong>t set probleem <strong>en</strong> e<strong>en</strong> getal k; stelt één <strong>van</strong> de<br />

blader<strong>en</strong> <strong>van</strong> de boom e<strong>en</strong> onafhankelijke verzameling <strong>van</strong> meer dan k knop<strong>en</strong> voor?<br />

(e) Gegev<strong>en</strong> e<strong>en</strong> graaf G = (V, E) <strong>en</strong> e<strong>en</strong> getal k; bestaat de grootste onafhankelijke verzameling in<br />

G uit minder dan k knop<strong>en</strong>?<br />

(f) Gegev<strong>en</strong> e<strong>en</strong> collectie deelverzameling<strong>en</strong> {Si}i <strong>van</strong> U = {u1, . . . , un}; bestaat er e<strong>en</strong> W ⊆ U zo<br />

dat |W ∩ Si | = 1 voor alle i?<br />

124


6.7 NP-problem<strong>en</strong> <strong>en</strong> de Praktijk<br />

In de vorige sectie hebb<strong>en</strong> we <strong>van</strong> e<strong>en</strong> aantal problem<strong>en</strong> aangetoond dat ze NP-volledig zijn. E<strong>en</strong> NPvolledigheidsbewijs<br />

voor e<strong>en</strong> probleem wordt doorgaans gegev<strong>en</strong> om aan te gev<strong>en</strong> dat e<strong>en</strong> algoritmische<br />

aanpak <strong>van</strong> het probleem weinig zin heeft. In de praktijk echter kunn<strong>en</strong> we vaak niet ervoor kiez<strong>en</strong> om e<strong>en</strong><br />

probleem maar te lat<strong>en</strong> ligg<strong>en</strong> als het algoritmisch moelijk blijkt te zijn. E<strong>en</strong> NP-volledigheidsbewijs is dan<br />

ook veel meer e<strong>en</strong> aanleiding om naar alternatieve oplossing<strong>en</strong> voor het probleem te zoek<strong>en</strong> nu is geblek<strong>en</strong><br />

dat zoek<strong>en</strong> naar e<strong>en</strong> effici<strong>en</strong>te algoritme voor het algem<strong>en</strong>e probleem waarschijnlijk hopeloos is. E<strong>en</strong> paar<br />

mogelijke uitweg<strong>en</strong> zijn.<br />

1. Probeer e<strong>en</strong> beperkte algoritme voor e<strong>en</strong> speciaal geval <strong>van</strong> het probleem te vind<strong>en</strong>. Als bijvoorbeeld<br />

het probleem het vind<strong>en</strong> <strong>van</strong> e<strong>en</strong> kleuring is, <strong>en</strong> het probleem beperkt kan word<strong>en</strong> tot planaire graf<strong>en</strong>,<br />

dan hoeft het probleem niet zo moeilijk te zijn.<br />

2. Probeer e<strong>en</strong> algoritme te vind<strong>en</strong> die in de meeste gevall<strong>en</strong> in polynomiale tijd werkt <strong>en</strong> alle<strong>en</strong> op e<strong>en</strong> (zo<br />

klein mogelijk) deel <strong>van</strong> de mogelijke invoer<strong>en</strong> exhaustive search gebruikt (<strong>en</strong> dus expon<strong>en</strong>tieel is). E<strong>en</strong><br />

bek<strong>en</strong>d voorbeeld hier<strong>van</strong> is de in de economie gebruikte simplex algoritme voor lineair programmer<strong>en</strong>.<br />

Voor e<strong>en</strong> lineaire functie in n variabel<strong>en</strong> zoekt m<strong>en</strong> e<strong>en</strong> optimale waarde die voldoet aan e<strong>en</strong> serie<br />

lineaire beperking<strong>en</strong>. De lineaire beperking<strong>en</strong> kunn<strong>en</strong> in n dim<strong>en</strong>sies gezi<strong>en</strong> word<strong>en</strong> als e<strong>en</strong> polytoop<br />

waarop de lineaire functie gedefinieerd is. E<strong>en</strong> extreme waarde wordt dan altijd aang<strong>en</strong>om<strong>en</strong> in één <strong>van</strong><br />

de hoekpunt<strong>en</strong> <strong>van</strong> het polytoop. E<strong>en</strong> algoritme om het maximum te bepal<strong>en</strong> is dus <strong>van</strong> het <strong>en</strong>e naar<br />

het andere hoekpunt lop<strong>en</strong> om te kijk<strong>en</strong> waar het maximum wordt aang<strong>en</strong>om<strong>en</strong>. Dit is precies wat de<br />

simplexalgoritme, met behup <strong>van</strong> e<strong>en</strong> aantal lineaire transformaties, doet. De algoritme is e<strong>en</strong>voudig<br />

te implem<strong>en</strong>ter<strong>en</strong> <strong>en</strong> te begrijp<strong>en</strong> <strong>en</strong> voor kleine gevall<strong>en</strong> (niet teveel beperking<strong>en</strong>) zelfs met de hand<br />

makkelijk uit te voer<strong>en</strong>. Er zijn gevall<strong>en</strong> te construer<strong>en</strong> waarin de algoritme expon<strong>en</strong>tiële looptijd heeft,<br />

maar deze kom<strong>en</strong> in de praktijk niet voor. Daarom is deze methode, hoewel er al lang e<strong>en</strong> polynomiaal<br />

begr<strong>en</strong>sde algoritme voor dit probleem bestaat [Kha80], nog steeds in gebruik.<br />

3. Probeer e<strong>en</strong> algoritme te vind<strong>en</strong> die gebruik maakt <strong>van</strong> coinflips, zó dat die algoritme voor alle inputs<br />

in de meeste gevall<strong>en</strong> in polynomiale tijd werkt. Sinds <strong>en</strong>ige tijd is bek<strong>en</strong>d dat primaliteitstest<strong>en</strong> in<br />

polynomiale tijd kan [AKS04]. De algoritme hiervoor is echter nog niet wijdverbreid geïmplem<strong>en</strong>teerd,<br />

misschi<strong>en</strong> ook omdat de snelste algoritm<strong>en</strong> hoewel polynomiaal nog steeds <strong>van</strong> vrij hoge graad zijn.<br />

Probabilistische algoritm<strong>en</strong> voor primaliteitstest<strong>en</strong> als in deze tekst beschrev<strong>en</strong> zijn wel wijdverbreid,<br />

gemakkelijk te implem<strong>en</strong>ter<strong>en</strong> <strong>en</strong> ruim voorhand<strong>en</strong>. Daarom zijn deze, hoewel in principe expon<strong>en</strong>tieel,<br />

nog steeds zeer in trek.<br />

4. Probeer e<strong>en</strong> algoritme te vind<strong>en</strong> die e<strong>en</strong> suboptimale oplossing geeft. De problem<strong>en</strong> die we in dit<br />

hoofdstuk besprok<strong>en</strong> hebb<strong>en</strong> zijn alle beslissingsproblem<strong>en</strong>. Bestaat er, is er etc. Nauw verwant<br />

met deze problem<strong>en</strong> zijn de optimaliseringsproblem<strong>en</strong>. Wat is de kortste route door e<strong>en</strong> volledige<br />

gewog<strong>en</strong> graaf langs alle punt<strong>en</strong>, wat is de verzameling object<strong>en</strong> in de knapsack die het grootste<br />

gewicht kleiner dan b geeft, wat is de kleinste verzameling knop<strong>en</strong> die e<strong>en</strong> vertex cover <strong>van</strong> de graaf<br />

geeft etc. Het is duidelijk dat als het optimaliseringsprobleem polynomiale tijd begr<strong>en</strong>sd is, dat dan ook<br />

het beslissingsprobleem polynomiale tijd begr<strong>en</strong>sd is <strong>en</strong> omgekeerd (via binary search). Echter als het<br />

beslissingsprobleem moelijk is, dan hoeft het niet altijd zo te zijn dat het optimaliseringsprobleem ook<br />

moelijk is. Mits niet gevraagd wordt naar de beste oplossing, maar bijvoorbeeld naar e<strong>en</strong> acceptabele<br />

oplossing.<br />

6.7.1 SAT, KNAPSACK, <strong>en</strong> VC<br />

Soms bestaan er e<strong>en</strong>voudige gulzige algoritm<strong>en</strong> die weliswaar niet e<strong>en</strong> optimaal resultaat gev<strong>en</strong>, maar toch<br />

e<strong>en</strong> resultaat in de buurt <strong>van</strong> e<strong>en</strong> oplossing. We hebb<strong>en</strong> al eerder gezi<strong>en</strong> dat SAT met twee variabel<strong>en</strong> per<br />

zin e<strong>en</strong> probleem in P is geword<strong>en</strong>, net zoals bijvoorbeeld tweekleurbaarheid. De NP-volledige variant <strong>van</strong><br />

SAT, die met meer variabel<strong>en</strong> per zin, heeft weliswaar ge<strong>en</strong> polynomiale algoritme, maar met e<strong>en</strong> e<strong>en</strong>voudige<br />

deterministische algoritme kan toch e<strong>en</strong> verrass<strong>en</strong>d resultaat behaald word<strong>en</strong>. Neem e<strong>en</strong> SAT formule <strong>van</strong> m<br />

125


zinn<strong>en</strong>. Elke toewijzing <strong>van</strong> waarheidswaard<strong>en</strong> vervult e<strong>en</strong> fractie <strong>van</strong> die zinn<strong>en</strong>. Als de formule vervulbaar<br />

is, dan is er minst<strong>en</strong>s één toewijzing die ze allemaal vervult. Er is e<strong>en</strong> deterministische algoritme die t<strong>en</strong>minste<br />

de helft <strong>van</strong> het maximaal aantal vervulbare zinn<strong>en</strong> vervult. Als volgt: Als x1 = 1 meer dan de helft <strong>van</strong><br />

de zinn<strong>en</strong> waarin x1 voorkomt verult, zet dan x1 = 1, anders zet x1 = 0. Schrap alle zinn<strong>en</strong> die aldus<br />

waargemaakt zijn <strong>en</strong> ga door met x2.<br />

Voor 3SAT is de situatie nog interessanter dan voor SAT. Als je maar 3 variabel<strong>en</strong> per zin hebt, dan<br />

is er maar 1 <strong>van</strong> de 8 mogelijke toewijzing<strong>en</strong> <strong>van</strong> waarheidswaard<strong>en</strong> aan die variabel<strong>en</strong>, die die zin onwaar<br />

maakt. Dat betek<strong>en</strong>t dat de kans dat e<strong>en</strong> random toewijzing de zin waarmaakt 7/8 is. Weg<strong>en</strong>s het feit dat<br />

de verwachtingswaarde e<strong>en</strong> lineaire functie is, maakt dit dat de verwachting dat e<strong>en</strong> willekeurige toewijzing<br />

<strong>van</strong> waarheidswaard<strong>en</strong> fractie waargemaakte zinn<strong>en</strong> door e<strong>en</strong> willekeurige toewijzing <strong>van</strong> waarheidswaard<strong>en</strong><br />

7/8 is.<br />

Voor Vertex Cover bestaat ook simpele algoritme. Begin met e<strong>en</strong> lege verzameling VC. Neem e<strong>en</strong> willekeurige<br />

kant, stop beide eindpunt<strong>en</strong> in VC <strong>en</strong> schrap vervolg<strong>en</strong>s deze kant <strong>en</strong> alle kant<strong>en</strong> die in die eindpunt<strong>en</strong><br />

uitkom<strong>en</strong>. Ga verder totdat de graaf ge<strong>en</strong> kant<strong>en</strong> meer heeft. De geproduceerde verzameling VC bestaat uit<br />

e<strong>en</strong> verzameling eindpunt<strong>en</strong> <strong>van</strong> losse kant<strong>en</strong>, e<strong>en</strong> matching. Omdat elke vertex cover (ook de minimale) <strong>van</strong><br />

elke kant t<strong>en</strong>minste één eindpunt heeft, zit precies de helft <strong>van</strong> alle punt<strong>en</strong> in VC ook in de minimale vertex<br />

cover (maar mogelijk meer) VC is dus e<strong>en</strong> vertex cover die hoogst<strong>en</strong>s twee keer zo groot is als de minimale.<br />

Hoewel Vertex Cover <strong>en</strong> Indep<strong>en</strong>d<strong>en</strong>t Set heel gemakkelijk tot elkaar te reducer<strong>en</strong> zijn, kunn<strong>en</strong> we e<strong>en</strong><br />

b<strong>en</strong>aderingsalgoritme voor Vertex Cover niet gebruik<strong>en</strong> om e<strong>en</strong> b<strong>en</strong>adering <strong>van</strong> Indep<strong>en</strong>d<strong>en</strong>t Set te verkrijg<strong>en</strong>.<br />

Stel dat we e<strong>en</strong> VC kunn<strong>en</strong> krijg<strong>en</strong> die ρ te slecht is, dus voor zekere ρ > 1 krijg<strong>en</strong> we in e<strong>en</strong> graaf met n<br />

knop<strong>en</strong> e<strong>en</strong> vertex cover <strong>van</strong> ρK als er e<strong>en</strong> vertex cover <strong>van</strong> K in zit. Als in e<strong>en</strong> graaf <strong>van</strong> n knop<strong>en</strong> e<strong>en</strong> IS<br />

<strong>van</strong> groote M zit, dan zit er in die graaf e<strong>en</strong> VC <strong>van</strong> grootte n − M. E<strong>en</strong> ρ slechte b<strong>en</strong>aderingsalgoritme zou<br />

dan e<strong>en</strong> VC <strong>van</strong> grootte ρ(n − M) gev<strong>en</strong>, die weer e<strong>en</strong> IS <strong>van</strong> grootte n − ρ(n − M) zou gev<strong>en</strong>. Hieraan zie<br />

je niet alle<strong>en</strong> dat M minst<strong>en</strong>s e<strong>en</strong> (ρ − 1)/ρ) fractie <strong>van</strong> n moet zijn om ueberhaupt e<strong>en</strong> garantie <strong>van</strong> meer<br />

dan 0 knop<strong>en</strong> in de indep<strong>en</strong>d<strong>en</strong>t set te krijg<strong>en</strong>, maar bov<strong>en</strong>di<strong>en</strong> dat de verkreg<strong>en</strong> b<strong>en</strong>aderingsfractie afhangt<br />

<strong>van</strong> n. Er kan word<strong>en</strong> bewez<strong>en</strong>, maar valt buit<strong>en</strong> deze tekst, dat voor indep<strong>en</strong>d<strong>en</strong>t set niet e<strong>en</strong> dergelijke<br />

b<strong>en</strong>aderingsalgoritme kan bestaan, t<strong>en</strong>zij P=NP.<br />

We hebb<strong>en</strong> voor KNAPSACK al gezi<strong>en</strong> dat, als b klein is, e<strong>en</strong> polynomiale algoritme gemaakt kan word<strong>en</strong><br />

met behulp <strong>van</strong> dynamic programming. Deze zelfde algoritme kan gebruikt word<strong>en</strong> om e<strong>en</strong> b<strong>en</strong>adering <strong>van</strong><br />

de optimale waarde in polynomiale tijd te krijg<strong>en</strong>. We definier<strong>en</strong> e<strong>en</strong>voudig e<strong>en</strong> getal K = ɛW/n waar W<br />

het maximale gewicht <strong>van</strong> alle object<strong>en</strong> is, del<strong>en</strong> vervolg<strong>en</strong>s alle waard<strong>en</strong> in het probleem door K <strong>en</strong> voer<strong>en</strong><br />

de dynamic programming algoritme uit. Deze levert e<strong>en</strong> optimale waarde O op die hoogst<strong>en</strong>s e<strong>en</strong> factor ɛ<br />

slechter is dan die <strong>van</strong> het oorspronkelijke probleem.<br />

6.7.2 E<strong>en</strong> b<strong>en</strong>adering voor TSP<br />

E<strong>en</strong> probleem dat zowel onder de eerste als de laatste categorie hierbov<strong>en</strong> valt is het handelsreizigerprobleem.<br />

Het algem<strong>en</strong>e geval <strong>van</strong> het handelsreizigerprobleem is moeilijk, NP-volledig. In de praktijk hebb<strong>en</strong> we echter<br />

vrijwel altijd te mak<strong>en</strong> met e<strong>en</strong> speciaal geval <strong>van</strong> het handelsreizigerprobleem, namelijk het probleem dat zich<br />

afspeelt op e<strong>en</strong> kaart, de Euclidische versie <strong>van</strong> het probleem. Dit probleem heeft doorgaans de eig<strong>en</strong>schap<br />

dat de driehoeksongelijkheid geldt. De som <strong>van</strong> de afstand<strong>en</strong> <strong>van</strong> A naar B <strong>en</strong> <strong>van</strong> B naar C is altijd groter<br />

dan of gelijk aan de afstand <strong>van</strong> A naar C. Op e<strong>en</strong> graaf waar de driehoeksongelijkheid geldt, kunn<strong>en</strong> we<br />

met behulp <strong>van</strong> e<strong>en</strong> algoritme voor e<strong>en</strong> bek<strong>en</strong>d probleem e<strong>en</strong> polynomiale tijd algoritme gev<strong>en</strong> voor het<br />

handelsreizigerprobleem die nooit slechter is dan tweemaal de optimale route voor het echte probleem. De<br />

algoritme die we gebruik<strong>en</strong> is één <strong>van</strong> de algoritm<strong>en</strong> voor de opspann<strong>en</strong>de boom <strong>van</strong> minimale kost<strong>en</strong> <strong>en</strong><br />

gaat als volgt.<br />

1: input e<strong>en</strong> volledige gewog<strong>en</strong> graaf K waarin de driehoeksongelijkheid geldt.<br />

2: Berek<strong>en</strong> e<strong>en</strong> opspann<strong>en</strong>de boom <strong>van</strong> K.<br />

3: Verdubbel alle kant<strong>en</strong>.<br />

4: Begin e<strong>en</strong> cykel in e<strong>en</strong> kant <strong>en</strong> loop telk<strong>en</strong>s naar de volg<strong>en</strong>de knoop <strong>en</strong> markeer deze als “bezocht”.<br />

5: Sla in de cykel reeds bezochte knop<strong>en</strong> over door naar de volg<strong>en</strong>de knoop te spring<strong>en</strong>. Daarbij verwijder<strong>en</strong><br />

we de twee kant<strong>en</strong> in de opspann<strong>en</strong>de boom <strong>en</strong> ver<strong>van</strong>g<strong>en</strong> deze door één kant uit K. Zonodig wordt deze<br />

126


operatie herhaald uitgevoerd.<br />

•<br />

6<br />

3<br />

1<br />

•<br />

•<br />

2<br />

5<br />

4<br />

•<br />

•<br />

3<br />

1<br />

•<br />

•<br />

2<br />

•<br />

•<br />

��<br />

3<br />

Figuur 6.10: Van graaf naar TSP cykel<br />

Figuur 6.10 geeft e<strong>en</strong> voorbeeldje <strong>van</strong> de transformatie <strong>van</strong> graaf naar spanning tree naar cykel.<br />

6.7.3 Branch <strong>en</strong> Bound<br />

Het doorzoek<strong>en</strong> <strong>van</strong> alle mogelijke oplossing<strong>en</strong> voor e<strong>en</strong> NP-volledig probleem komt vaak neer op het doorzoek<strong>en</strong><br />

<strong>van</strong> e<strong>en</strong> expon<strong>en</strong>tieel grote boom. Bijvoorbeeld het zoek<strong>en</strong> <strong>van</strong> e<strong>en</strong> oplossing voor SATISFIABILITY<br />

kunn<strong>en</strong> we opvatt<strong>en</strong> als e<strong>en</strong> boom doordat we zegg<strong>en</strong> dat we eerst voor de waarde x1 = 0 alle mogelijke oplossing<strong>en</strong><br />

voor x2, . . . , xn prober<strong>en</strong> om vervolg<strong>en</strong>s voor alle oplossing<strong>en</strong> bij x1 = 1 alle oplossing<strong>en</strong> voor x2 t.e.m.<br />

xn prober<strong>en</strong>. We reducer<strong>en</strong> als het ware het oploss<strong>en</strong> <strong>van</strong> het probleem SATISFIABILITY tot het oploss<strong>en</strong><br />

<strong>van</strong> twee e<strong>en</strong>voudiger problem<strong>en</strong>, dat wil zegg<strong>en</strong> problem<strong>en</strong> met minder variabel<strong>en</strong>. Zulke problem<strong>en</strong> zijn<br />

onder de NP-volledige problem<strong>en</strong> zeer talrijk. We noem<strong>en</strong> dit soort problem<strong>en</strong> zelf-reduceerbaar(zie 6.5.2).<br />

We kunn<strong>en</strong> ze oploss<strong>en</strong> door het antwoord te zoek<strong>en</strong> op problem<strong>en</strong> <strong>van</strong> dezelfde soort maar <strong>van</strong> kleinere om<strong>van</strong>g.<br />

Dit soort problem<strong>en</strong> le<strong>en</strong>t zich uiteraard expliciet voor recursieve programma’s, al kost zo’n recursief<br />

programma in het onderhavige geval natuurlijk wel expon<strong>en</strong>tiële tijd.<br />

In het geval <strong>van</strong> optimaliseringsproblem<strong>en</strong> kunn<strong>en</strong> we misschi<strong>en</strong> wat aan die expon<strong>en</strong>tiële tijd do<strong>en</strong>, omdat<br />

we, althans in de meeste gevall<strong>en</strong>, niet de gehele zoekruimte hoev<strong>en</strong> te doorlop<strong>en</strong>. Als voorbeeld nem<strong>en</strong> we<br />

weer het handelsreiziger probleem. Hoe is het handelsreizigerprobleem zelfreduceerbaar? We besprek<strong>en</strong> twee<br />

method<strong>en</strong>. Allereerst moet<strong>en</strong> we <strong>van</strong> elke stad naar e<strong>en</strong> andere stad totdat e<strong>en</strong> rondje gemaakt is. Om e<strong>en</strong><br />

stad te bezoek<strong>en</strong> hebb<strong>en</strong> we de keuze uit elk <strong>van</strong> zijn bur<strong>en</strong>. Kiez<strong>en</strong> we e<strong>en</strong> buur, dan betek<strong>en</strong>t dat dat we<br />

alle andere bur<strong>en</strong> niet kiez<strong>en</strong> (behalve op de terugweg natuurlijk). Als we kiez<strong>en</strong> voor b als buur <strong>van</strong> a dan<br />

betek<strong>en</strong>t dat dat de minimaal mogelijke tour met het gewicht <strong>van</strong> de kant (a, b) to<strong>en</strong>eemt. Als we zo e<strong>en</strong><br />

aantal kant<strong>en</strong> gekoz<strong>en</strong> hebb<strong>en</strong> wet<strong>en</strong> we dus dat de minimale tour langs die kant<strong>en</strong> groter dan of gelijk is<br />

aan de som <strong>van</strong> de gewicht<strong>en</strong> <strong>van</strong> die kant<strong>en</strong>. De branch heuristiek laat ons telk<strong>en</strong>s kiez<strong>en</strong> de knoop in de<br />

zoekboom verder te ontwikkel<strong>en</strong> waarvoor deze waarde minimaal is. Hebb<strong>en</strong> we op deze manier e<strong>en</strong>maal<br />

n − 2 knop<strong>en</strong> gekoz<strong>en</strong>, dan ligt de laatste knoop in het rijtje vast <strong>en</strong> kunn<strong>en</strong> we de l<strong>en</strong>gte <strong>van</strong> de gekoz<strong>en</strong><br />

tour uitrek<strong>en</strong><strong>en</strong>, de bound heuristiek zegt dan dat ge<strong>en</strong> <strong>en</strong>kele knoop in de boom waar<strong>van</strong> de minimaal te<br />

verwacht<strong>en</strong> waarde groter dan of gelijk is aan de waarde <strong>van</strong> zo’n complete tour verder uitgewerkt moet<br />

word<strong>en</strong>. Op deze manier voorkom<strong>en</strong> we in veel gevall<strong>en</strong> dat we de complete boom moet<strong>en</strong> doorzoek<strong>en</strong>.<br />

Aangezi<strong>en</strong> alle mogelijke pad<strong>en</strong> nog steeds in de boom voorkom<strong>en</strong>, is de worst-case complexiteit <strong>van</strong> deze<br />

aanpak echter nog steeds n!.<br />

Voorbeeld 6.7.1: Stel e<strong>en</strong> afstandstabel tuss<strong>en</strong> vijf sted<strong>en</strong> is als volgt gegev<strong>en</strong>:<br />

A B C D E<br />

A - 3 16 3 20<br />

B 5 - 6 1 17<br />

C 14 4 - 19 5<br />

D 1 2 1 - 4<br />

E 2 1 1 19 -<br />

De branch & bound algoritme die we hierbov<strong>en</strong> hebb<strong>en</strong> beschrev<strong>en</strong> produceert dan de volg<strong>en</strong>de zoekboom:<br />

127<br />

1<br />

��<br />

•�� •<br />

2<br />

6<br />

��<br />


28<br />

14<br />

C<br />

9<br />

4<br />

B<br />

D<br />

5<br />

20<br />

8<br />

3<br />

A<br />

16<br />

3 20<br />

C D<br />

E B<br />

11<br />

D E C E C E B E B C<br />

35 34 12 23 18 37 33 20 28 18<br />

We behandel<strong>en</strong> aan de hand <strong>van</strong> dit voorbeeld nog e<strong>en</strong> andere methode om branch & bound te spel<strong>en</strong><br />

met het handelsreizigerprobleem. In plaats <strong>van</strong> dat we telk<strong>en</strong>s e<strong>en</strong> buur <strong>van</strong> e<strong>en</strong> stad kiez<strong>en</strong> kunn<strong>en</strong> we voor<br />

elke kant kiez<strong>en</strong> dat die wel of ge<strong>en</strong> deel uitmaakt <strong>van</strong> e<strong>en</strong> rondje. Dat heeft voor- <strong>en</strong> nadel<strong>en</strong>. Aan de <strong>en</strong>e<br />

kant wordt de breedte <strong>van</strong> de zoekboom kleiner (er zijn twee keuzemogelijkhed<strong>en</strong>), aan de andere kant is<br />

de algoritme wat ingewikkelder. We nem<strong>en</strong> hetzelfde voorbeeld. De wel/niet keuze voor de kant<strong>en</strong> lat<strong>en</strong><br />

we langs de rij<strong>en</strong> lop<strong>en</strong> (dus eerst kant (A,B), dan (A,C) etc. De keuze voor kant (A,B) in het rondje sluit<br />

onmiddellijk de kant<strong>en</strong> (A,C), (A,D), <strong>en</strong> (A,E) uit <strong>en</strong> maakt de minimaal te bereik<strong>en</strong> tour t<strong>en</strong>minste 3, de<br />

keuze teg<strong>en</strong> (A,B) sluit (A,B) uit <strong>en</strong> maakt de minimaal te bereik<strong>en</strong> tour ook 3, maar nu omdat dat het<br />

minimum gewicht <strong>van</strong> de kant<strong>en</strong> (A,C), (A,D), <strong>en</strong> (A,E) is. Als vier kant<strong>en</strong> zijn opg<strong>en</strong>om<strong>en</strong> is de vierde<br />

verplicht <strong>en</strong> de l<strong>en</strong>gte <strong>van</strong> de tour bek<strong>en</strong>d. De diepte <strong>van</strong> de boom kan nu echter groter zijn dan 4, omdat<br />

negatieve keuz<strong>en</strong> zijn opg<strong>en</strong>om<strong>en</strong>. We lat<strong>en</strong> steeds de linkertak de positieve keuze voor de kant zijn <strong>en</strong> de<br />

rechtertak de negatieve keuze. We krijg<strong>en</strong> dan de volg<strong>en</strong>de zoekboom:<br />

28<br />

BC<br />

9<br />

CD<br />

14<br />

AB<br />

3 3<br />

4<br />

BD<br />

4<br />

34 DC<br />

5<br />

9<br />

AC<br />

16<br />

BE<br />

20<br />

3<br />

AD<br />

3<br />

12 24 ∞ ∞<br />

Ook hier zi<strong>en</strong> we (gelukkig) dat de optimale route l<strong>en</strong>gte 12 heeft <strong>en</strong> langs de kant<strong>en</strong> AB, BD, DC (<strong>en</strong> CE, <strong>en</strong><br />

EA) voert. Ook krijg<strong>en</strong> we hier e<strong>en</strong> werkelijke verbetering <strong>van</strong> de worst-case complexiteit. Als er n knop<strong>en</strong><br />

in de graaf zijn, zijn er namelijk O(n2 ) kant<strong>en</strong>. Dat betek<strong>en</strong>t dat onze algoritme e<strong>en</strong> worst-case complexiteit<br />

heeft <strong>van</strong> O(2n2) nog steeds aanzi<strong>en</strong>lijk, maar e<strong>en</strong> opmerkelijke verbetering t<strong>en</strong> opzichte <strong>van</strong> O(n!). ✷<br />

De oplett<strong>en</strong>de lezer zal hier opmerk<strong>en</strong> dat de eerder besprok<strong>en</strong> A ∗ algoritme (zie 3.2) niet veel meer is<br />

dan het toepass<strong>en</strong> <strong>van</strong> het Branch & bound principe op kortste pad<strong>en</strong> in graf<strong>en</strong>.<br />

128<br />

22<br />

AE<br />

20<br />

5<br />

C<br />

9<br />

14<br />

14<br />

7<br />

E<br />

E<br />

8<br />

8


Deel III<br />

Extra Onderwerp<strong>en</strong><br />

129


In dit deel <strong>van</strong> de tekst behandel<strong>en</strong> we e<strong>en</strong> aantal onderwerp<strong>en</strong> die te mak<strong>en</strong> hebb<strong>en</strong> met geheug<strong>en</strong>complexiteit<br />

<strong>van</strong> problem<strong>en</strong>. Geheug<strong>en</strong>complexiteit is e<strong>en</strong> andere belangrijke maat voor de complexiteit<br />

<strong>van</strong> algoritm<strong>en</strong> <strong>en</strong> problem<strong>en</strong>, maar de onderwerp<strong>en</strong> die de tijdcomplexiteit betreff<strong>en</strong> vull<strong>en</strong> doorgaans e<strong>en</strong><br />

inleid<strong>en</strong>de cursus geheel. Als er tijd over is omdat bijvoorbeeld aan het begin wat sneller gegaan kan word<strong>en</strong><br />

als het publiek wat meer voork<strong>en</strong>nis heeft zoud<strong>en</strong> deze onderwerp<strong>en</strong> niettemin aan bod kunn<strong>en</strong> kom<strong>en</strong>. Ook<br />

valt te d<strong>en</strong>k<strong>en</strong> aan het bestuder<strong>en</strong> <strong>van</strong> deze onderwerp<strong>en</strong> achteraf in het kader <strong>van</strong> zelfstudie. In dit deel<br />

zijn vooralsnog ge<strong>en</strong> somm<strong>en</strong> opg<strong>en</strong>om<strong>en</strong>.<br />

131


132


Hoofdstuk 7<br />

Meer <strong>Complexiteit</strong>sklass<strong>en</strong><br />

In dit hoofdstuk zull<strong>en</strong> we e<strong>en</strong> aantal complexiteitsklass<strong>en</strong> besprek<strong>en</strong> die niet onmiddelijk onderwerp zijn<br />

in e<strong>en</strong> inleid<strong>en</strong>de cursus <strong>Algoritm<strong>en</strong></strong> <strong>en</strong> <strong>Complexiteit</strong>. Tijd is e<strong>en</strong> belangrijke complexiteitsmaat, maar er<br />

is natuurlijk ook nog e<strong>en</strong> aantal andere mat<strong>en</strong> <strong>van</strong> complexiteit die we aan algoritm<strong>en</strong> kunn<strong>en</strong> met<strong>en</strong>.<br />

Geheug<strong>en</strong>complexiteit is daar één <strong>van</strong>, maar ook de grootte <strong>van</strong> circuits die nodig is om e<strong>en</strong> probleem aan te<br />

pakk<strong>en</strong> is e<strong>en</strong> belangrijke complexiteitsmaat in het kader <strong>van</strong> de afmeting<strong>en</strong> <strong>van</strong> special purpose hardware.<br />

De diepte <strong>van</strong> e<strong>en</strong> circuit (langste pad in e<strong>en</strong> graaf) is e<strong>en</strong> maat voor de parallelle complexiteit <strong>van</strong> e<strong>en</strong><br />

probleem, of de mate waarin e<strong>en</strong> algoritme voor e<strong>en</strong> probleem wel of niet geparallelliseerd kan word<strong>en</strong>. In<br />

Hoofdstuk 6 hebb<strong>en</strong> we gezi<strong>en</strong> dat we de moelijkheid <strong>van</strong> problem<strong>en</strong> kunn<strong>en</strong> aanton<strong>en</strong> door reductie <strong>van</strong> e<strong>en</strong><br />

NP-volledig probleem. Voor parallellizeerbaarheid is e<strong>en</strong> soortgelijk gereedschap voorhand<strong>en</strong>. We kunn<strong>en</strong><br />

de inher<strong>en</strong>te sequ<strong>en</strong>tialiteit (ontmoediging voor het zoek<strong>en</strong> naar parallelle algoritm<strong>en</strong>) door e<strong>en</strong> reductie <strong>van</strong><br />

e<strong>en</strong> circuitprobleem te gev<strong>en</strong> die dan niet in polynomiale tijd, maar in logarithmisch begr<strong>en</strong>sd geheug<strong>en</strong> is<br />

uit te voer<strong>en</strong>. Zo e<strong>en</strong> reductie toont de P-volledigheid <strong>van</strong> e<strong>en</strong> probleem aan. Veel <strong>van</strong> deze reducties kunn<strong>en</strong><br />

gevond<strong>en</strong> word<strong>en</strong> in het boek [GHR95]. Vooralsnog besprek<strong>en</strong> we dit onderwerp niet in deze tekst.<br />

7.1 Geheug<strong>en</strong>begr<strong>en</strong>sde Klass<strong>en</strong><br />

Als teg<strong>en</strong>hanger <strong>van</strong> Polynomiale tijd in het domein <strong>van</strong> de geheug<strong>en</strong>begr<strong>en</strong>sde theorie bekijk<strong>en</strong> we Polynomiaal<br />

geheug<strong>en</strong>, PSPACE. Het is duidelijk dat alles dat in polynomiaal begr<strong>en</strong>sde tijd kan ook in polynomiaal<br />

begr<strong>en</strong>sd geheug<strong>en</strong> kan. Immers, e<strong>en</strong> Turing machine kan in één stap niet meer dan één nieuwe geheug<strong>en</strong>cel<br />

aansprek<strong>en</strong>. Aan de bov<strong>en</strong>kant is polynomiaal begr<strong>en</strong>sd geheug<strong>en</strong> begr<strong>en</strong>sd door expon<strong>en</strong>tiële tijd. Dit is in<br />

te zi<strong>en</strong> door naar het Turing machinemodel te kijk<strong>en</strong>. E<strong>en</strong> standaard Turingmachine wordt op één bepaald<br />

mom<strong>en</strong>t in de tijd geheel beschrev<strong>en</strong> door de inhoud <strong>van</strong> de band op dat mom<strong>en</strong>t, de toestand waarin de<br />

Turingmachine zich op dat mom<strong>en</strong>t bevindt, <strong>en</strong> de plaats waar de tapekop op dat mom<strong>en</strong>t op de band staat.<br />

Laat het bandalfabet {0, 1} zijn, het toestandsalfabet Q <strong>en</strong> het aantal cell<strong>en</strong> op de band begr<strong>en</strong>sd door het<br />

polynoom p, d.w.z. voor één of andere n kunn<strong>en</strong> nooit meer dan p(n) cell<strong>en</strong> in gebruik zijn, dan volgt dat<br />

er niet meer dan |Q| × p(n) × 2 p(n) <strong>van</strong> dit soort beschrijving<strong>en</strong> bestaan. E<strong>en</strong> expon<strong>en</strong>tiële tijd begr<strong>en</strong>sde<br />

machine kan <strong>van</strong> de beginconfiguratie e<strong>en</strong> voldo<strong>en</strong>de aantal <strong>van</strong> deze configuraties doorrek<strong>en</strong><strong>en</strong> om erachter<br />

te kom<strong>en</strong> of onderweg e<strong>en</strong> accepter<strong>en</strong>de toestand bereikt wordt. Na hoogst<strong>en</strong>s |Q| × p(n) × 2 p(n) moet zo’n<br />

toestand immmers bereikt word<strong>en</strong>, of de machine raakt in e<strong>en</strong> (oneindige) loop.<br />

7.2 PSPACE<br />

De natuurlijke teg<strong>en</strong>hanger <strong>van</strong> P in het geheug<strong>en</strong>begr<strong>en</strong>sde domein is de klasse <strong>van</strong> problem<strong>en</strong> die kunn<strong>en</strong><br />

word<strong>en</strong> opgelost door Turingmachines waarbij het geheug<strong>en</strong>gebruik begr<strong>en</strong>sd wordt door e<strong>en</strong> polynoom in de<br />

l<strong>en</strong>gte <strong>van</strong> de invoer. Deze klasse noem<strong>en</strong> we PSPACE. Zoals hierbov<strong>en</strong> beargum<strong>en</strong>teerd geldt P ⊆ PSPACE<br />

<strong>en</strong> PSPACE ⊆ EXP, maar omdat ook geldt P �= EXP (zie 6.1) geldt niet “P = PSPACE <strong>en</strong> PSPACE =<br />

133


EXP”. Eén <strong>van</strong> de twee inclusies moet e<strong>en</strong> ongelijkheid zijn, maar welke <strong>van</strong> de twee is één <strong>van</strong> de grote<br />

op<strong>en</strong> problem<strong>en</strong> <strong>van</strong> onze tijd. Voor polynomiaalbegr<strong>en</strong>sde geheug<strong>en</strong>complexiteit geldt echter wel invariantie<br />

onder nondeterminisme. Er is dus ge<strong>en</strong> P = NP? probleem in de geheug<strong>en</strong>complexiteit, ofwel NPSPACE<br />

bestaat niet als aparte <strong>en</strong>titeit, zoals de volg<strong>en</strong>de stelling tot uitdrukking br<strong>en</strong>gt.<br />

Stelling 7.2.1 PSPACE = NPSPACE.<br />

Om deze stelling te bewijz<strong>en</strong> merk<strong>en</strong> we op, net zoals in het bewijs <strong>van</strong> PSPACE ⊆ EXP dat als e<strong>en</strong><br />

geheug<strong>en</strong>begr<strong>en</strong>sde Turing machine e<strong>en</strong> accepter<strong>en</strong>de berek<strong>en</strong>ing heeft, er e<strong>en</strong> expon<strong>en</strong>tieel begr<strong>en</strong>sde verzameling<br />

polynomiaal begr<strong>en</strong>sde mom<strong>en</strong>topnames <strong>van</strong> deze Turing machine moet zijn die achter elkaar gezet<br />

zo’n accepter<strong>en</strong>de berek<strong>en</strong>ing vorm<strong>en</strong>. Anders is er e<strong>en</strong> cykel <strong>en</strong> zal de Turing machine niet accepter<strong>en</strong>. Voor<br />

e<strong>en</strong> nondeterministische machine is dit argum<strong>en</strong>t e<strong>en</strong> fractie subtieler. Als er e<strong>en</strong> accepter<strong>en</strong>de berek<strong>en</strong>ing<br />

bestaat die langer is dan e<strong>en</strong> <strong>van</strong>tevor<strong>en</strong> te gev<strong>en</strong> expon<strong>en</strong>tieel aantal mom<strong>en</strong>topnames, dan zit daar e<strong>en</strong> cykel<br />

in, <strong>en</strong> is er dus ook e<strong>en</strong> kortere accepter<strong>en</strong>de berek<strong>en</strong>ing (waar die cykel niet in zit). De kortste accepter<strong>en</strong>de<br />

berek<strong>en</strong>ing zal ge<strong>en</strong> cyckel hebb<strong>en</strong> <strong>en</strong> minder dan expon<strong>en</strong>tieel veel mom<strong>en</strong>topnames bevatt<strong>en</strong>.<br />

Stel dus er is e<strong>en</strong> expon<strong>en</strong>tiële verzameling C1, . . . , C 2 p(n) mom<strong>en</strong>topnames ieder <strong>van</strong> l<strong>en</strong>gte hoogst<strong>en</strong>s p(n)<br />

die sam<strong>en</strong> accepter<strong>en</strong>de berek<strong>en</strong>ing <strong>van</strong> machine M op invoer x vorm<strong>en</strong>. We bewer<strong>en</strong> dat het bestaan <strong>van</strong><br />

zo’n verzameling kan word<strong>en</strong> berek<strong>en</strong>d door e<strong>en</strong> polynomiaal geheug<strong>en</strong>begr<strong>en</strong>sde deterministische machine<br />

M ′ , ofwel dat <strong>van</strong> elke nondeterministische polynomiaal geheug<strong>en</strong>begr<strong>en</strong>sde machine M <strong>en</strong> invoer x door<br />

e<strong>en</strong> deterministische polynomiaal geheug<strong>en</strong>begr<strong>en</strong>sde machine M ′ kan word<strong>en</strong> bepaald of M ′ de invoer x kan<br />

accepter<strong>en</strong>.<br />

Merk op dat e<strong>en</strong> verzameling C1, . . . , C 2 p (n) bestaat, als <strong>en</strong> alle<strong>en</strong> als er e<strong>en</strong> C 2 p(n−1) bestaat, zo dat<br />

C1, . . . , C 2 p(n−1) e<strong>en</strong> legitieme ope<strong>en</strong>volging <strong>van</strong> mom<strong>en</strong>topnames <strong>van</strong> M op invoer x is <strong>en</strong> C 2 p(n−1), . . . , C 2 p(n)<br />

e<strong>en</strong> legitieme ope<strong>en</strong>volging <strong>van</strong> mom<strong>en</strong>topnames <strong>van</strong> M op invoer x is. We gebruik<strong>en</strong> deze observatie voor<br />

de definitie <strong>van</strong> de volg<strong>en</strong>de recursieve procedure.<br />

1: Procedure Comp(C1,C2,n).<br />

2: if n = 0 th<strong>en</strong><br />

3: if C2 is a legal successor of C1 according to M th<strong>en</strong><br />

4: return(1);<br />

5: else<br />

6: return(0);<br />

7: <strong>en</strong>d if<br />

8: else<br />

9: return( � {[Comp(C1, Ck, n − 1) ∧ Comp(Ck, C2, n − 1)] : Ck a legal configuration of M})<br />

10: <strong>en</strong>d if<br />

Door deze routine aan te roep<strong>en</strong> met Comp(C0, Cacc, p(n)) kunn<strong>en</strong> we besliss<strong>en</strong> of er e<strong>en</strong> accepter<strong>en</strong>de<br />

berek<strong>en</strong>ing bestaatn <strong>van</strong> 2 p(n) mom<strong>en</strong>topnames. Vooropgesteld dat de recursieve boom in deze algoritme<br />

verstandig doorlop<strong>en</strong> wordt, kan ze geheel in polynomiaal begr<strong>en</strong>sd geheug<strong>en</strong> word<strong>en</strong> uitgevoerd. Immers,<br />

elke Ck in regel 9 is slechts p(n) groot, <strong>en</strong> verder is de recursiediepte begr<strong>en</strong>sd door p(n), zodat de totale<br />

berek<strong>en</strong>ing kan word<strong>en</strong> uitgevoerd in O(p 2 (n)) begr<strong>en</strong>sd geheug<strong>en</strong>.<br />

7.2.1 Volledige Problem<strong>en</strong><br />

Ook voor PSPACE zijn er volledige problem<strong>en</strong> bek<strong>en</strong>d. De meeste zijn zog<strong>en</strong>oemde two person perfect<br />

information games. E<strong>en</strong> master probleem voor PSPACE is het acceptatieprobleem <strong>van</strong> e<strong>en</strong> lineair begr<strong>en</strong>sde<br />

Turing machine, het model voor het herk<strong>en</strong>n<strong>en</strong> <strong>van</strong> context s<strong>en</strong>sitieve tal<strong>en</strong>. Het eerste, meest bek<strong>en</strong>de,<br />

karakterizer<strong>en</strong>de probleem voor PSPACE is echter dat <strong>van</strong> de logische predikat<strong>en</strong>, quantified boolean formulae<br />

(QBF).<br />

naam: QBF<br />

gegev<strong>en</strong>: E<strong>en</strong> gekwantificeerde logische formule P = Q1Q2 . . . QnF (x1, . . . , xn), met Qi ∈ {∃, ∀}.<br />

gevraagd: Is P waar?<br />

134


De eerste stap is, is QBF e<strong>en</strong> probleem in PSPACE? Dat is iets minder makkelijk dan de vergelijkbare<br />

stap voor NP-volledige problem<strong>en</strong>, maar ook weer niet heel erg moeilijk. Immers wanneer is<br />

P = Q1Q2 . . . QnF (x1, . . . , xn) waar? Dat hangt <strong>van</strong> Q1 af. Als Q1 = ∀, dan is P waar d.e.s.d.a.<br />

Q2, . . . , QnF (0, x2, . . . , xn) waar is <strong>en</strong> Q2, . . . , QnF (0, x2, . . . , xn) waar is, <strong>en</strong> als Q1 = ∃ dan is P waar<br />

d.e.s.d.a. Q2, . . . , QnF (0, x2, . . . , xn) waar is of Q2, . . . , QnF (0, x2, . . . , xn) waar is. De volg<strong>en</strong>de procedure<br />

beslist dus of e<strong>en</strong> predicaat waar is.<br />

1: Procedure QBF(Q1 . . . QnF (x0, . . . , xn))<br />

2: if Q1 = ∀ th<strong>en</strong><br />

3: return(QBF(Q2 . . . Qn(F (0, x2, . . . , xn) ∧ Q2 . . . Qn(F (0, x2, . . . , xn))<br />

4: else if Q1 = ∃ th<strong>en</strong><br />

5: return(QBF(Q2 . . . Qn(F (0, x2, . . . , xn) ∨ Q2 . . . Qn(F (0, x2, . . . , xn))<br />

6: else<br />

7: return(F (x1, . . . , xn)) //no quantifiers left, all x have values.<br />

8: <strong>en</strong>d if<br />

De recursiediepte is n, <strong>en</strong> elk elem<strong>en</strong>t op de stapel <strong>van</strong> de aanroep<strong>en</strong> kan in polynomiaal geheug<strong>en</strong> word<strong>en</strong><br />

opgeslag<strong>en</strong>. Het geheug<strong>en</strong>gebruik is dus ongeveer kwadratisch, <strong>en</strong> dus zeker polynomiaal.<br />

Dat elk probleem dat door e<strong>en</strong> Turing machine kan word<strong>en</strong> opgelost vertaald kan word<strong>en</strong> naar e<strong>en</strong> QBF<br />

die waar is als <strong>en</strong> alle<strong>en</strong> als de invoer geaccepteerd wordt zi<strong>en</strong> we aan de hand <strong>van</strong> het eerder gegev<strong>en</strong> bewijs<br />

voor PSPACE ⊆ EXP. E<strong>en</strong> mom<strong>en</strong>topname <strong>van</strong> e<strong>en</strong> Turingmachine kan word<strong>en</strong> vertaald naar e<strong>en</strong> logische<br />

formule zoals we hebb<strong>en</strong> gezi<strong>en</strong> in 6.5. Twee configuraties kunn<strong>en</strong> naar e<strong>en</strong> logische formule vertaald word<strong>en</strong><br />

die alle<strong>en</strong> e<strong>en</strong> vervulling heeft als de twee configuraties legale opvolgers zijn <strong>van</strong> elkaar volg<strong>en</strong>s het programma<br />

<strong>van</strong> de Turing machine. Laat Q0 e<strong>en</strong> logische formule zijn die de begintoestand <strong>van</strong> M repres<strong>en</strong>teeert, <strong>en</strong> QF<br />

e<strong>en</strong> logische formule zijn die de eindtoestand repres<strong>en</strong>teerd. Laat verder S(F1(x1, . . . , xn), F2(y1, . . . , ym))<br />

zo zijn dat (∃x1, . . . , xn, y1 . . . ym)[S(F1(x1, . . . , xn), F2(y1, . . . , ym))] dan <strong>en</strong> slechts dan als F1(x1, . . . , xn)<br />

<strong>en</strong> F2(y1, . . . , ym) voor deze x <strong>en</strong> y ope<strong>en</strong>volg<strong>en</strong>de of dezelfde mom<strong>en</strong>topnames <strong>van</strong> M repres<strong>en</strong>ter<strong>en</strong>. We<br />

definier<strong>en</strong> de formules Sk(P1, P2) voor predikat<strong>en</strong> met of zonder quantor<strong>en</strong> P1 <strong>en</strong> P2 als:<br />

�<br />

Sk =<br />

S(P1, P2) if k = 0<br />

(∃P3)[Sk−1(P1, P3) ∧ Sk−1(P3, P2)] anders<br />

De Turingmachine heeft e<strong>en</strong> accepter<strong>en</strong>de berek<strong>en</strong>ing <strong>van</strong> l<strong>en</strong>gte 2 n dan <strong>en</strong> slechts dan als Sn(Q0, QF ).<br />

Helaas is dit nog niet e<strong>en</strong> polynomiale tijd begr<strong>en</strong>sde vertaling. Immers Sn is twee keer zolang als Sn−1<br />

waardoor Sn l<strong>en</strong>gte Ω(2 n ) krijgt <strong>en</strong> dat mag niet in e<strong>en</strong> polynomiaal begr<strong>en</strong>sde reductie. We merk<strong>en</strong> echter<br />

op dat Sk−1 twee keer gebruikt wordt, <strong>en</strong> dit kan word<strong>en</strong> beperkt tot één keer door e<strong>en</strong> extra universele<br />

quantor te gebruik<strong>en</strong> als volgt.<br />

(∃P3)[(∀P4P5)[Sk−1(P4, P5) ∨ [(P4 �= P1 ∨ P5 �= P3) ∧ (P4 �= P3 ∨ P5 �= P 2)]]<br />

Als P1 = P4 <strong>en</strong> P3 = P5, dan moet Sk−1(P4, P5) waar zijn, <strong>en</strong> dus ook Sk−1(P1, P3). Hetzelfde geldt voor<br />

P3 <strong>en</strong> P2. De reductie heeft nu nog maar één optred<strong>en</strong> <strong>van</strong> de formule Sk−1 <strong>en</strong> dus wordt de uiteindelijke<br />

formule ook polynomiaal in l<strong>en</strong>gte in de l<strong>en</strong>gte <strong>van</strong> de invoer.<br />

7.2.2 Andere PSPACE Volledige Problem<strong>en</strong><br />

Zoals we al hebb<strong>en</strong> opgemerkt zijn veel <strong>van</strong> de bek<strong>en</strong>de PSPACE volledige problem<strong>en</strong> variant<strong>en</strong> <strong>van</strong> spelletjes,<br />

<strong>en</strong> wel de zog<strong>en</strong>oemde two person perfect information games. De intuitie hierbij is dat deze spell<strong>en</strong> vaak de<br />

volg<strong>en</strong>de vorm hebb<strong>en</strong>. Er is e<strong>en</strong> winn<strong>en</strong>de strategie alle<strong>en</strong> als er e<strong>en</strong> zet voor speler 1 is, zodat voor elke<br />

zet <strong>van</strong> speler 2 er weer e<strong>en</strong> zet voor speler 1 is zodat,... Kortom, deze spel<strong>en</strong> hebb<strong>en</strong> de structuur <strong>van</strong> QBF<br />

<strong>en</strong> het is dan ook niet verwonderlijk dat QBF vaak vertaald kan word<strong>en</strong> naar de vraag ” is er e<strong>en</strong> winn<strong>en</strong>de<br />

strategie” voor zo’n spel.<br />

Het eerste spel dat we zull<strong>en</strong> bekijk<strong>en</strong> wordt gespeeld op graf<strong>en</strong> <strong>en</strong> heet G<strong>en</strong>eralized Geography. Geography<br />

is e<strong>en</strong> bek<strong>en</strong>d spel dat vaak gespeeld wordt om de verveling te verdrijv<strong>en</strong> gedur<strong>en</strong>de lange autoritt<strong>en</strong>.<br />

De spelers mog<strong>en</strong> geografische nam<strong>en</strong> (bijvoorbeeld sted<strong>en</strong>) noem<strong>en</strong> die erg<strong>en</strong>s in de wereld voorkom<strong>en</strong>. Het<br />

135


gaat erom dat de volg<strong>en</strong>de speler steeds e<strong>en</strong> naam moet noem<strong>en</strong> die begint met de letter waarmee de vorige<br />

naam geëindigd is. De speler die ge<strong>en</strong> nieuwe naam aan de lijst kan toevoeg<strong>en</strong> verliest.<br />

We modeler<strong>en</strong> het spel met e<strong>en</strong> gerichte graaf waarin de knop<strong>en</strong> alle sted<strong>en</strong>nam<strong>en</strong> ter wereld zijn, e<strong>en</strong><br />

kant gaat <strong>van</strong> stad A naar stad B als de naam <strong>van</strong> A eindigt met de letter waarmee de naam <strong>van</strong> B begint.<br />

E<strong>en</strong> <strong>van</strong> de sted<strong>en</strong> wordt als startpunt aangewez<strong>en</strong>. Er zijn twee spelers P1 <strong>en</strong> P2 <strong>en</strong> de vraag is heeft P1<br />

e<strong>en</strong> winn<strong>en</strong>de strategie, d.w.z. kan zij voor elke strategie die P2 kan hebb<strong>en</strong> e<strong>en</strong> verzameling knop<strong>en</strong> vind<strong>en</strong><br />

zo dat P2 vastloopt. We gev<strong>en</strong> e<strong>en</strong> klein voorbeeld.<br />

Voorbeeld 7.2.1:<br />

<strong>Amsterdam</strong><br />

��<br />

��<br />

Muid<strong>en</strong> Maastricht<br />

��<br />

Nijmeg<strong>en</strong><br />

��<br />

��<br />

Naard<strong>en</strong><br />

��<br />

��<br />

T egel<strong>en</strong><br />

Voorbeeld <strong>van</strong> e<strong>en</strong> mogelijk verloop <strong>van</strong> Geography. ✷<br />

G<strong>en</strong>eralized Geography wordt gespeeld op e<strong>en</strong> gerichte graaf met e<strong>en</strong> speciale knoop start. Speler 1<br />

begint met het kiez<strong>en</strong> <strong>van</strong> e<strong>en</strong> buur <strong>van</strong> start <strong>en</strong> om beurt<strong>en</strong> kiez<strong>en</strong> spelers e<strong>en</strong> buur <strong>van</strong> e<strong>en</strong> knoop die de<br />

vorige speler gekoz<strong>en</strong> heeft. Als e<strong>en</strong> speler gedwong<strong>en</strong> is e<strong>en</strong> knoop met uitgraad 0 te kiez<strong>en</strong>, of e<strong>en</strong> knoop<br />

die al eerder gekoz<strong>en</strong> is, dan heeft zij verlor<strong>en</strong>. Het probleem is nu.<br />

naam: G<strong>en</strong>eralized Geography<br />

gegev<strong>en</strong>: E<strong>en</strong> gerichte graaf met startpunt s<br />

gevraagd: Heeft Speler 1 e<strong>en</strong> winn<strong>en</strong>de strategie<br />

We moet<strong>en</strong> eerst bewijz<strong>en</strong> dat GG in PSPACE zit. Daartoe gev<strong>en</strong> we e<strong>en</strong> simpele recursieve algoritme die<br />

berek<strong>en</strong>t of Speler 1 e<strong>en</strong> winn<strong>en</strong>de strategie heeft. Omdat elke knoop slechts één keer gekoz<strong>en</strong> kan word<strong>en</strong>,<br />

<strong>en</strong> er eindig veel knop<strong>en</strong> in de graaf zitt<strong>en</strong> heeft één <strong>van</strong> beide spelers altijd e<strong>en</strong> winn<strong>en</strong>de strategie. E<strong>en</strong><br />

antwoord op de vraag dat e<strong>en</strong> algoritme inhoudt is dus: ” Speler 1 heeft e<strong>en</strong> winn<strong>en</strong>de strategie, dan <strong>en</strong><br />

slechts dan als Speler 2 dat niet heeft.” We vertal<strong>en</strong> dit als volgt naar e<strong>en</strong> algoritme die de gegev<strong>en</strong> vraag<br />

onderzoekt op het bestaan <strong>van</strong> e<strong>en</strong> winn<strong>en</strong>de strategie.<br />

1: GG(knoop)<br />

2: if knoop has no outgoing edges th<strong>en</strong><br />

3: return(reject)<br />

4: else if (∀ neighbors n of knoop)GG(n)=reject th<strong>en</strong><br />

5: return(accept)<br />

6: else<br />

7: return(reject)<br />

8: <strong>en</strong>d if<br />

GG(start) onderzoekt of speler 1 <strong>van</strong>uit de startknoop e<strong>en</strong> winn<strong>en</strong>de strategie heeft. Het is duidelijk dat<br />

deze algoritme in polynomiale ruimte kan word<strong>en</strong> uitgevoerd <strong>en</strong> dus dat ons probleem in PSPACE zit.<br />

Vervolg<strong>en</strong>s bewijz<strong>en</strong> we dat GG volledig is voor PSPACE. We do<strong>en</strong> dit door e<strong>en</strong> reductie <strong>van</strong> e<strong>en</strong> spelvorm<br />

<strong>van</strong> QBF. Gegev<strong>en</strong> e<strong>en</strong> formule met kwantor<strong>en</strong> Q1x1Q2x2 . . . QnxnF (x1, . . . , xn) dan mak<strong>en</strong> we voor elke<br />

kwantor in de formule de volg<strong>en</strong>de graaf.<br />

136


��<br />

��<br />

��<br />

��<br />

Verder zijn er 2n knop<strong>en</strong> xi <strong>en</strong> xi voor de n variabel<strong>en</strong> <strong>en</strong> hun ontk<strong>en</strong>ning, <strong>en</strong> m knop<strong>en</strong> voor de zinn<strong>en</strong>. De<br />

zin knop<strong>en</strong> cj hebb<strong>en</strong> uitgraad 3 <strong>en</strong> zijn verbond<strong>en</strong> met de variabele knop<strong>en</strong> of hun ontk<strong>en</strong>ning al naar gelang<br />

ze in de zin voorkom<strong>en</strong>. De zin cj knop<strong>en</strong> zijn via één <strong>en</strong>kele <strong>en</strong>kele kant verbond<strong>en</strong> met e<strong>en</strong> keuzeknoop c.<br />

We gev<strong>en</strong> weer e<strong>en</strong> klein voorbeeld.<br />

Voorbeeld 7.2.2: Laat gegev<strong>en</strong> zijn de formule (∃x1∀x2∃x3)[(x1 ∨ x2 ∨ x3) ∧ (x1 ∨ x2 ∨ x3)]. De reductie<br />

hierbov<strong>en</strong> gegev<strong>en</strong> vertaalt dit naar de volg<strong>en</strong>de graaf.<br />

s<br />

��<br />

��<br />

��<br />

��<br />

��<br />

��<br />

��<br />

��<br />

��<br />

��<br />

��<br />

��<br />

��<br />

��<br />

��<br />

��<br />

��<br />

x1<br />

��<br />

x1 ��<br />

c1<br />

��<br />

��<br />

Eerst stell<strong>en</strong> we ev<strong>en</strong> vast dat het predicaat in dit voorbeeld waar is. Immers als je x3 waar kiest, dan doet<br />

het er niet toe wat de andere twee variabel<strong>en</strong> voor waarde aannem<strong>en</strong>. Dus P1 moet e<strong>en</strong> winn<strong>en</strong>de strategie<br />

hebb<strong>en</strong>. De strategie is als volgt. P1 kiest in de deelgraf<strong>en</strong> die e<strong>en</strong> exist<strong>en</strong>tiële kwantor verteg<strong>en</strong>woordig<strong>en</strong>,<br />

de waarde <strong>van</strong> de variabele die zij waar wil mak<strong>en</strong> om het predicaat waar te krijg<strong>en</strong>. P2 kiest in de deelgraf<strong>en</strong><br />

de waarde <strong>van</strong> de variabele die zij onwaar wil mak<strong>en</strong> om het predicaat onwaar te krijg<strong>en</strong>. P1 begint, door<br />

voor x1 linksaf te gaan (waar) of rechtsaf te gaan (onwaar). In dit speciale geval doet dat er niet toe. Wat<br />

137<br />

x2<br />

x1<br />

x2<br />

x3<br />

��<br />

��<br />

��<br />

��<br />

��<br />

c2<br />

��<br />

��<br />

c<br />

��


P2 bij de volg<strong>en</strong>de deelgraaf doet, doet er niet toe. P1 moet vervolg<strong>en</strong>s bij de laatste deelgraaf wel linksaf<br />

slaan. P1 kiest gedwong<strong>en</strong> de knoop c, <strong>en</strong> P2 kan nu één <strong>van</strong> de zinn<strong>en</strong> kiez<strong>en</strong> door c1 of c2 te kiez<strong>en</strong>. Omdat<br />

de formule waar is, doet het er in dit geval niet toe welke <strong>van</strong> de twee zij kiest. Als ze c1 kiest, dan moet<br />

vervolg<strong>en</strong>s Speler 1 e<strong>en</strong> variabele kiez<strong>en</strong> die waar is. Als zij x1 waar gekoz<strong>en</strong> heeft, dan kan zij knoop x1<br />

kiez<strong>en</strong>, als zij x1 echter onwaar gekoz<strong>en</strong> heeft, dan kan zij de knoop x1 kiez<strong>en</strong>. In beide gevall<strong>en</strong> verliest P2<br />

omdat de volg<strong>en</strong>de knoop reeds eerder gekoz<strong>en</strong> is. Kiest P2 voor c2 dan kiest P1 vervolg<strong>en</strong>s x3 <strong>en</strong> bereikt<br />

hetzelfde resultaat. ✷<br />

E<strong>en</strong> lange lijst <strong>van</strong> PSPACE volledige spelletjes bestaat. We noem<strong>en</strong> er e<strong>en</strong> paar:<br />

1. Amazons [Bur00, Hea05]<br />

2. Go[LS80]<br />

3. Hex [ET76]<br />

4. Othello [IK94]<br />

5. Rush Hour [FHN + 03]<br />

6. Shanghai [CFLS97]<br />

7. Sokoban [Cul99]<br />

De werkelijke lijst is nog veel langer. Behalve in de wereld <strong>van</strong> de spelletjes kom<strong>en</strong> we PSPACE volledigheid<br />

ook in de taalherk<strong>en</strong>ning teg<strong>en</strong>. Naarmate e<strong>en</strong> probleem meer uitdrukkingskracht heeft wordt het<br />

computationeel ook moelijker. Programmeertal<strong>en</strong> word<strong>en</strong> vaak zoveel mogelijk contextvrij gehoud<strong>en</strong> omdat<br />

dat het compiler<strong>en</strong> makkelijker maakt. Als voor de betek<strong>en</strong>is <strong>van</strong> e<strong>en</strong> statem<strong>en</strong>t niet de context uitvoerig<br />

hoeft te word<strong>en</strong> onderzocht kan word<strong>en</strong> volstaan met e<strong>en</strong> one-pass compiler of e<strong>en</strong> interpreter. Natuurlijke<br />

tal<strong>en</strong> zijn context-s<strong>en</strong>sitief. Computationeel betek<strong>en</strong>t dit e<strong>en</strong> sprong <strong>van</strong> polynomiaal beslisbaar voor<br />

contextvrije tal<strong>en</strong> naar PSPACE-volledigheid voor de context gevoelige tal<strong>en</strong>.<br />

Ook in de logica kom<strong>en</strong> we PSPACE volledigheid op meer plaats<strong>en</strong> teg<strong>en</strong> dan alle<strong>en</strong> in de predicat<strong>en</strong>logica.<br />

Veel <strong>van</strong> de logica’s die met modale of temporele kwantor<strong>en</strong> gedefinieerd word<strong>en</strong> zijn PSPACE volledig of<br />

soms nog complexer.<br />

7.3 LOGSPACE<br />

Zon beetje de kleinste klasse die we machinemodelonafhankelijk kunn<strong>en</strong> definiër<strong>en</strong> is de klasse <strong>van</strong> tal<strong>en</strong><br />

beslisbaar in (deterministische) logaritmische ruimte. Omdat de Stelling <strong>van</strong> Savitch, hierbov<strong>en</strong>, e<strong>en</strong> O(n 2 )<br />

overhead heeft <strong>van</strong> deterministisch naar nondeterministisch, is er ook e<strong>en</strong> klasse NLOGSPACE <strong>van</strong> problem<strong>en</strong><br />

beslisbaar in nondeterministisch logarithmische ruimte. Het probleem NLOGSPACE ? = LOGSPACE is<br />

vooralsnog e<strong>en</strong> op<strong>en</strong> probleem, al zijn er deelresultat<strong>en</strong> behaald [Rei05].<br />

Wel is bek<strong>en</strong>d dat NLOGSPACE geslot<strong>en</strong> is onder complem<strong>en</strong>tatie. Dat wil zegg<strong>en</strong> dat het complem<strong>en</strong>t<br />

<strong>van</strong> elke context s<strong>en</strong>sitieve taal zelf ook weer e<strong>en</strong> context s<strong>en</strong>sitieve taal is. Voor dit probleem (dat 23 jaar<br />

op<strong>en</strong> heeft gestaan) is in 1988 door N. Immerman [Imm88] <strong>en</strong> onafhankelijk door R.Szelepsc<strong>en</strong>yi [Sze87]<br />

e<strong>en</strong> techniek ontwikkeld die sindsdi<strong>en</strong> inductive counting g<strong>en</strong>oemd wordt. We gev<strong>en</strong> hier e<strong>en</strong> schets <strong>van</strong> het<br />

bewijs.<br />

Stel we hebb<strong>en</strong> gegev<strong>en</strong> <strong>van</strong> e<strong>en</strong> nondeterministische machine M e<strong>en</strong> mom<strong>en</strong>topname (configuratie) c<br />

<strong>en</strong> we vrag<strong>en</strong> ons af of e<strong>en</strong> bepaalde configuratie d <strong>van</strong>uit c bereikt kan word<strong>en</strong>. We kunn<strong>en</strong> dan nondeterministisch<br />

e<strong>en</strong> aantal tuss<strong>en</strong>configuraties c1, c2, . . . , ck met c1 = c, ck = d <strong>en</strong> elke configuratie ci+1 is in<br />

één stap <strong>van</strong>uit ci te bereik<strong>en</strong>. Het aantal configuraties kan beperkt blijv<strong>en</strong> tot n als M e<strong>en</strong> machine is die<br />

in LOGSPACE werkt. Stel dat we precies wet<strong>en</strong> hoeveel configuraties <strong>van</strong>uit c bereikt kunn<strong>en</strong> word<strong>en</strong>, <strong>en</strong><br />

138


we will<strong>en</strong> bewijz<strong>en</strong> dat e<strong>en</strong> configuratie d niet <strong>van</strong>uit c bereikt kan word<strong>en</strong>. E<strong>en</strong> nondeterministische machine<br />

kan dan het gegev<strong>en</strong> aantal verschill<strong>en</strong>de configuraties bepal<strong>en</strong>, bewijz<strong>en</strong> dat deze alle <strong>van</strong>uit c bereikt<br />

kunn<strong>en</strong> word<strong>en</strong> <strong>en</strong> daarmee dus dat d niet zo’n configuratie is.<br />

Stel nu dat we will<strong>en</strong> bewijz<strong>en</strong> dat e<strong>en</strong> invoer x niet geaccepteerd wordt door M in e<strong>en</strong> LOGSPACE<br />

begr<strong>en</strong>sde berek<strong>en</strong>ing. We moet<strong>en</strong> dan bewijz<strong>en</strong> dat in LOGSPACE ge<strong>en</strong> configuratie met e<strong>en</strong> accepter<strong>en</strong>de<br />

toestand <strong>van</strong>uit de begintoestand kan word<strong>en</strong> bereikt. We wet<strong>en</strong> hoeveel configuraties er <strong>van</strong>uit de<br />

begintoestand in één stap kunn<strong>en</strong> word<strong>en</strong> bereikt <strong>en</strong> we bewer<strong>en</strong> (inductie) dat we als we wet<strong>en</strong> hoeveel<br />

verschill<strong>en</strong>de configuraties uit de begintoestand in k stapp<strong>en</strong> bereikt kunn<strong>en</strong> word<strong>en</strong>, dat we dan ook wet<strong>en</strong><br />

hoeveel configuraties er in k + 1 stapp<strong>en</strong> <strong>van</strong>uit de begintoestand bereikt kunn<strong>en</strong> word<strong>en</strong>.<br />

Het bewijs voor deze bewering is de volg<strong>en</strong>de methode. Gegev<strong>en</strong> dat er bijvoorbeeld i configuraties in k<br />

stapp<strong>en</strong> <strong>van</strong>uit de begintoestand bereikt kunn<strong>en</strong> word<strong>en</strong>. G<strong>en</strong>ereer achtere<strong>en</strong>volg<strong>en</strong>s al deze configuraties <strong>en</strong><br />

bewijs dat dit die configuraties zijn door voor elk <strong>van</strong> die configuraties k − 1 tuss<strong>en</strong>configuraties te rad<strong>en</strong>,<br />

waartuss<strong>en</strong> de overgang in één stap kan gebeur<strong>en</strong>. Nu kunn<strong>en</strong> we voor elk <strong>van</strong> die configuraties apart<br />

bepal<strong>en</strong> hoeveel opvolgers deze configuratie heeft, <strong>en</strong> daarmee dus hoeveel configuraties in k + 1 stapp<strong>en</strong><br />

kunn<strong>en</strong> word<strong>en</strong> bereikt.<br />

De machine die het complem<strong>en</strong>t <strong>van</strong> e<strong>en</strong> gegev<strong>en</strong> machine M berek<strong>en</strong>t, doet nu op invoer x het volg<strong>en</strong>de.<br />

1: Berek<strong>en</strong> hoeveel mogelijke verschill<strong>en</strong>de opvolgers de beginconfiguratie kan hebb<strong>en</strong> in n stapp<strong>en</strong>.<br />

2: G<strong>en</strong>ereer die configuraties (<strong>en</strong> bewijs dat het ze zijn)<br />

3: if Ge<strong>en</strong> <strong>van</strong> die configuraties accepter<strong>en</strong>d is th<strong>en</strong><br />

4: Accepteer<br />

5: else<br />

6: Verwerp<br />

7: <strong>en</strong>d if<br />

7.3.1 Complete Problem<strong>en</strong><br />

Het g<strong>en</strong>erieke complete probleem voor nondeterministische logaritmische ruimte is het probleem ST-connectivity.<br />

naam: ST-CONNECTIVITY<br />

gegev<strong>en</strong>: E<strong>en</strong> gerichte graaf met twee knop<strong>en</strong> S <strong>en</strong> T<br />

gevraagd: Is er <strong>en</strong> pad <strong>van</strong> S naar T<br />

Dit probleem kan in nondeterministisch logaritmische ruimte word<strong>en</strong> beslist. Immers, als de graaf gegev<strong>en</strong><br />

is, kan e<strong>en</strong> Turingmachine beginn<strong>en</strong> met e<strong>en</strong> 1 op de werkband <strong>en</strong> vervolg<strong>en</strong>s e<strong>en</strong> getal S rad<strong>en</strong>. Daarna<br />

controleert de machine dat S, i e<strong>en</strong> kant is in de graaf. De ruimte ing<strong>en</strong>om<strong>en</strong> door S kan vervolg<strong>en</strong>s hergebruikt<br />

word<strong>en</strong> om e<strong>en</strong> getal i2 te rad<strong>en</strong> <strong>en</strong> te controler<strong>en</strong> dat i, i2 e<strong>en</strong> kant is in de graaf. Daarna kan de<br />

ruimte gebruikt voor i word<strong>en</strong> hergebruikt. Zo voortgaande kan de nondeterministische machine uitkom<strong>en</strong><br />

bij T als er e<strong>en</strong> pad <strong>van</strong> S naar T bestaat <strong>en</strong> accpeter<strong>en</strong>. Als zo’n pad niet bestaat, dan faalt deze aanpak<br />

uiteraard. Alle gebruikte getall<strong>en</strong> zijn kleiner dan of gelijk aan het aantal knop<strong>en</strong> in de graaf, waardoor het<br />

gebruikte gegeug<strong>en</strong> begr<strong>en</strong>sd is in de logaritme <strong>van</strong> de afmeting<strong>en</strong> <strong>van</strong> de repres<strong>en</strong>tatie <strong>van</strong> de graaf op de<br />

invoerband. Hiermee is bewez<strong>en</strong> dat dit e<strong>en</strong> probleem in LOGSPACE is.<br />

Het probleem is echter ook LOGSPACE volledig. Om dit in te zi<strong>en</strong> moet<strong>en</strong> we, gegev<strong>en</strong> e<strong>en</strong> nondeterministische<br />

logarithmisch geheug<strong>en</strong>begr<strong>en</strong>se machine M <strong>en</strong> e<strong>en</strong> invoer x, e<strong>en</strong> graaf G(M, x) mak<strong>en</strong> met twee<br />

knop<strong>en</strong> S <strong>en</strong> T , zodat T <strong>van</strong>uit S bereikbaar is dan <strong>en</strong> slechts dan als M e<strong>en</strong> accepter<strong>en</strong>de berek<strong>en</strong>ing heeft.<br />

Natuurlijk zijn de knop<strong>en</strong> <strong>van</strong> G(M, x) configuraties <strong>van</strong> M op invoer x <strong>en</strong> is S de beginconfiguratie <strong>en</strong> T de<br />

eindconfiguratie. Elke configuratie heeft maar e<strong>en</strong> paar mogelijke opvolgers, die door e<strong>en</strong> deterministische<br />

logarithmisch geheug<strong>en</strong>begr<strong>en</strong>sde machine kunn<strong>en</strong> word<strong>en</strong> berek<strong>en</strong>d. We mog<strong>en</strong> echter niet de uitvoerband<br />

als geheug<strong>en</strong> gebruik<strong>en</strong>, omdat deze groter dan logaritmisch wordt. Dit probleem kunn<strong>en</strong> we onder<strong>van</strong>g<strong>en</strong><br />

door als repres<strong>en</strong>tatie <strong>van</strong> de output te kiez<strong>en</strong> voor de adjac<strong>en</strong>cy matrix. Elk <strong>van</strong> de getall<strong>en</strong> <strong>van</strong> 1 tot<br />

p(n) kan e<strong>en</strong> legale codering <strong>van</strong> e<strong>en</strong> configuratie <strong>van</strong> M zijn (dat hoeft natuurlijk niet, maar dat is voor de<br />

berek<strong>en</strong>ing <strong>van</strong> ge<strong>en</strong> belang). De algoritme wordt:<br />

1: for i = 1 to p(n) do<br />

2: for j = 1 to p(n) do<br />

139


3: if i to j is a legal transition th<strong>en</strong><br />

4: output 1;<br />

5: else<br />

6: output 0;<br />

7: <strong>en</strong>d if<br />

8: <strong>en</strong>d for<br />

9: <strong>en</strong>d for<br />

Deze algoritme output e<strong>en</strong> serie 0<strong>en</strong> <strong>en</strong> 1<strong>en</strong> die e<strong>en</strong> repres<strong>en</strong>tatie <strong>van</strong> de adjac<strong>en</strong>cymatrix <strong>van</strong> de configuraties<br />

<strong>van</strong> M op invoer x is. Zonder beperking der algeme<strong>en</strong>heid kunn<strong>en</strong> we aannem<strong>en</strong> dat hierin knoop 0 de<br />

beginconfiguratie <strong>van</strong> M voorstelt <strong>en</strong> knoop p(n) de eindconfiguratie. De vraag of M de invoer x accepteert<br />

is dan dezelfde als de vraag of <strong>van</strong>uit knoop 0 knoop p(n) bereikt kan word<strong>en</strong>. het geheug<strong>en</strong> dat nodig is, is<br />

slechts het geheug<strong>en</strong> voor de tellers i <strong>en</strong> j, dus zeker niet meer dan logarithmisch begr<strong>en</strong>sd geheug<strong>en</strong>.<br />

7.4 Interactieve Bewijz<strong>en</strong><br />

De vraag wat e<strong>en</strong> bewijs is, is e<strong>en</strong> heel oude vraag in de filosofie <strong>en</strong> misschi<strong>en</strong> wel de red<strong>en</strong> waarom de logica<br />

bedrev<strong>en</strong> wordt. Kern <strong>van</strong> de zaak is dat de één iets weet of d<strong>en</strong>kt te wet<strong>en</strong>, <strong>en</strong> dat zij de ander daar<strong>van</strong><br />

probeert te overtuig<strong>en</strong>. Doorgaans is er sprake <strong>van</strong> regels om ervoor te zorg<strong>en</strong> dat de bewijsvoering ordelijk<br />

verloopt. E<strong>en</strong> voorbeeld hier<strong>van</strong> is elke willekeurige sport waar elk <strong>van</strong> beide teg<strong>en</strong>standers de ander (<strong>en</strong><br />

mogelijk ook e<strong>en</strong> publiek) er<strong>van</strong> probeert te overtuig<strong>en</strong> sterker te zijn. In sommige gevall<strong>en</strong> is er uiteraard<br />

ook ge<strong>en</strong> sprake <strong>van</strong> regels, maar dan moet<strong>en</strong> achteraf de regels <strong>van</strong> de sam<strong>en</strong>leving word<strong>en</strong> toegepast, <strong>en</strong><br />

de politie eraan te pas kom<strong>en</strong>.<br />

Onderdeel <strong>van</strong> de regels is doorgaans e<strong>en</strong> stelsel <strong>van</strong> axioma’s. Dat zijn principes waarover partij<strong>en</strong><br />

<strong>van</strong>tevor<strong>en</strong> e<strong>en</strong> akkoord sluit<strong>en</strong> om ervoor te zorg<strong>en</strong> dat er t<strong>en</strong>minste e<strong>en</strong> basis voor e<strong>en</strong> gesprek is. Axioma’s<br />

zijn niet algeme<strong>en</strong> geld<strong>en</strong>de principes, getuige bijvoorbeeld de axioma’s <strong>van</strong> Euclides voor de meetkunde.<br />

Slechts voor het onderhavige bewijs (<strong>en</strong> misschi<strong>en</strong> e<strong>en</strong> heel stel bewijz<strong>en</strong>) geld<strong>en</strong> ze als absoluut. Het spel<br />

bestaat eruit <strong>van</strong>uit de axioma’s met gebruikmaking <strong>van</strong> de regels te kom<strong>en</strong> tot de uitspraak waar<strong>van</strong> m<strong>en</strong><br />

de ander wil overtuig<strong>en</strong>. Dit spel heet dan ” bewijz<strong>en</strong>” <strong>en</strong> het bewez<strong>en</strong>e heet e<strong>en</strong> stelling (of tautologie).<br />

E<strong>en</strong> groot probleem vormt het in de hand houd<strong>en</strong> <strong>van</strong> de bewijsdrift. Hoeveel bewijs moet geleverd word<strong>en</strong><br />

om de teg<strong>en</strong>stander te overtuig<strong>en</strong>? Vooral wanneer de stelling interessant is, dan kan de l<strong>en</strong>gte <strong>van</strong> het<br />

bewijs nogal uit de hand lop<strong>en</strong>. Treff<strong>en</strong>de voorbeeld<strong>en</strong> hier<strong>van</strong> zijn het bewijs <strong>van</strong> de vierkleurbaarheid <strong>van</strong><br />

planaire graf<strong>en</strong> <strong>van</strong> Appel <strong>en</strong> Hak<strong>en</strong> [AH77a, AH77b], Het bewijs <strong>van</strong> Robertson <strong>en</strong> Seymour over graaf<br />

minor<strong>en</strong> [RS83, RS04], <strong>en</strong> het bewijs <strong>van</strong> Wiles <strong>van</strong> de stelling <strong>van</strong> Fermat[CSS97]. Het probleem is het<br />

vind<strong>en</strong> <strong>van</strong> e<strong>en</strong> trade-off tuss<strong>en</strong> de mate <strong>van</strong> overtuigd rak<strong>en</strong> <strong>van</strong> de waarheid <strong>van</strong> de teg<strong>en</strong>stander, <strong>en</strong> de<br />

inspanning die de teg<strong>en</strong>stander moet lever<strong>en</strong> bij het controler<strong>en</strong> <strong>van</strong> het bewijs. Natuurlijk zijn ook hier<br />

omgevingsfactor<strong>en</strong> <strong>van</strong> invloed. Bij de controle <strong>van</strong> het bewijs <strong>van</strong> de Stelling <strong>van</strong> Fermat is e<strong>en</strong> schier<br />

onbegr<strong>en</strong>sde inspanning ter controle gerechtvaardigd, maar bij de pinautomaat geldt e<strong>en</strong> gemakkelijk te<br />

duplicer<strong>en</strong> code <strong>van</strong> vier cijfers als bewijs <strong>van</strong> id<strong>en</strong>titeit.<br />

Van nature hebb<strong>en</strong> bewijz<strong>en</strong> dus e<strong>en</strong> interactief karakter. De meest e<strong>en</strong>voudige vorm hier<strong>van</strong> is dat de<br />

<strong>en</strong>e partij het bewijs op het bord schrijft <strong>en</strong> de andere partij zegt ” ja”. Dit kan echter alle<strong>en</strong> gedaan word<strong>en</strong><br />

als het bewijs klein g<strong>en</strong>oeg is om op e<strong>en</strong> bord te schrijv<strong>en</strong>. Anders word<strong>en</strong> del<strong>en</strong> <strong>van</strong> het bewijs weggelat<strong>en</strong><br />

<strong>en</strong> wordt het aan de andere partij gelat<strong>en</strong> over del<strong>en</strong> die zij niet begrijpt of niet gelooft door te vrag<strong>en</strong>. Als<br />

bewijz<strong>en</strong> klein g<strong>en</strong>oeg zijn (in onze traditie polynomiaal <strong>van</strong> l<strong>en</strong>gte) dan gev<strong>en</strong> we ze in één keer. De hele actie<br />

<strong>van</strong> bewijs vind<strong>en</strong> <strong>en</strong> verifiër<strong>en</strong> is dan e<strong>en</strong> NP-proces geword<strong>en</strong>. Als bewijz<strong>en</strong> langer (expon<strong>en</strong>tieel langer)<br />

word<strong>en</strong>, dan moet<strong>en</strong> we teruggrijp<strong>en</strong> op het pres<strong>en</strong>ter<strong>en</strong> <strong>van</strong> del<strong>en</strong> <strong>van</strong> het bewijs in e<strong>en</strong> vraag antwoord<br />

spel. Zo’n bewijs is e<strong>en</strong> echt interactief bewijs.<br />

7.5 Zero Knowledge<br />

E<strong>en</strong> zeer bijzondere tak <strong>van</strong> sport wordt gevormd door de zog<strong>en</strong>oemde zero-knowledge bewijz<strong>en</strong>. Het gaat er<br />

hierbij om e<strong>en</strong> interactief bewijs te gev<strong>en</strong> waarbij ge<strong>en</strong> k<strong>en</strong>nis over de aard <strong>van</strong> het bewijs wordt overgedrag<strong>en</strong>.<br />

140


Het protocol bestaat, zoals gebruikelijk in interactieve bewijz<strong>en</strong> uit e<strong>en</strong> serie uitdaging<strong>en</strong> <strong>en</strong> antwoord<strong>en</strong>, maar<br />

de antwoord<strong>en</strong> moet<strong>en</strong> altijd zo zijn dat de uitdager die ook zelf had kunn<strong>en</strong> gev<strong>en</strong>. De uitdager mag dus<br />

ge<strong>en</strong> k<strong>en</strong>nis kunn<strong>en</strong> ontl<strong>en</strong><strong>en</strong> aan het gegev<strong>en</strong> antwoord. Dat deze vorm <strong>van</strong> bewijz<strong>en</strong> <strong>van</strong> grote waarde is in<br />

het interactieve dataverkeer behoeft nauwelijks betoog. Immers e<strong>en</strong> afgeluisterde communicatie verschaft de<br />

afluisteraar bij dergelijke protocoll<strong>en</strong> per definitie niet de informatie nodig om bij misleiding te gebruik<strong>en</strong>.<br />

Er zijn twee soort<strong>en</strong> <strong>van</strong> deze zero knowledge protocoll<strong>en</strong>. Er is de absolute zero-knowledge—ongeacht<br />

hoeveel computing power de teg<strong>en</strong>partij of afluisteraar heeft, zij zal nooit iets ler<strong>en</strong> uit het protocol—<strong>en</strong> er<br />

is de relatieve zero-knowledge—als we er<strong>van</strong>uit gaan de dat de computing power <strong>van</strong> de teg<strong>en</strong>partij redelijk<br />

begr<strong>en</strong>sd is, zij kan bijvoorbeeld ge<strong>en</strong> NP-volledige problem<strong>en</strong> krak<strong>en</strong>, dan zal zij uit de communicatie niets<br />

ler<strong>en</strong> dat zij tot haar voordeel kan gebruik<strong>en</strong>.<br />

Voorbeeld 7.5.1: Als voorbeeld gev<strong>en</strong> we e<strong>en</strong> voorbeeld <strong>van</strong> relatieve zero-knowledge, gebaseerd op het<br />

HAMILTON CIRCUIT probleem. Zij gegev<strong>en</strong> e<strong>en</strong> graaf G = (V, E). Speler 2 beweert dat G e<strong>en</strong> Hamilton<br />

circuit heeft <strong>en</strong> dat zij dat Hamilton circuit k<strong>en</strong>t. Hoe zal zij speler 1 hier<strong>van</strong> overtuig<strong>en</strong> zonder het Hamilton<br />

circuit prijs te gev<strong>en</strong>. Dit gaat als volgt. Speler 2 produceert e<strong>en</strong> random permutatie <strong>van</strong> G die zij vervolg<strong>en</strong>s<br />

aan speler 1 stuurt. Deze heeft nu de keuze uit twee uitdaging<strong>en</strong> waaruit zij random kiest (e<strong>en</strong> andere strategie<br />

is alle<strong>en</strong> voordelig voor e<strong>en</strong> leug<strong>en</strong>achtige speler 2).<br />

1. Uitdaging 1 is: produceer de permutatie die <strong>van</strong> G de graaf G ′ maakt.<br />

2. Uitdaging 2 is: geef e<strong>en</strong> Hamilton circuit in graaf G ′ .<br />

Als speler 2 inderdaad e<strong>en</strong> Hamilton circuit k<strong>en</strong>t, dan kan zij in daar<strong>van</strong> e<strong>en</strong> Hamilton circuit in G ′<br />

construer<strong>en</strong>. Aang<strong>en</strong>om<strong>en</strong> dat speler 1 niet voldo<strong>en</strong>de rek<strong>en</strong>kracht heeft om het, moeilijk geachte, graf<strong>en</strong>isomorfie<br />

probleem op te loss<strong>en</strong>, zal speler 1 niets ler<strong>en</strong> over het Hamilton circuit in G uit het antwoord op<br />

uitdaging 2. Uiteraard kan speler 1 ook niets ler<strong>en</strong> uit het antwoord op uitdaging 1. E<strong>en</strong> random permutatie<br />

<strong>van</strong> G had zij immers zelf ook kunn<strong>en</strong> mak<strong>en</strong>. ✷<br />

Voorbeeld 7.5.2: Het in het vorige voorbeeld g<strong>en</strong>oemde graf<strong>en</strong>isomorfie probleem kan word<strong>en</strong> gebruikt als<br />

id<strong>en</strong>tificatieprotocol als volgt. Speler 1 produceert e<strong>en</strong> grote graaf G <strong>en</strong> e<strong>en</strong> permutatie <strong>van</strong> deze graaf G ′ .<br />

Aangezi<strong>en</strong> graf<strong>en</strong>isomorfie e<strong>en</strong> moeilijk probleem is is het niet iedere<strong>en</strong> gegev<strong>en</strong> de isomorfie tuss<strong>en</strong> G <strong>en</strong><br />

G ′ te berek<strong>en</strong><strong>en</strong>, maar Speler 1 k<strong>en</strong>t deze natuurlijk. Nu word<strong>en</strong> G <strong>en</strong> G ′ teg<strong>en</strong>over Speler 2 gebruikt om<br />

Speler 1 te id<strong>en</strong>tificer<strong>en</strong> als volgt. Speler 1 produceert e<strong>en</strong> derde graaf G ′′ die e<strong>en</strong> permutatie <strong>van</strong> G of <strong>van</strong><br />

G ′ is (dat maakt voor beide spelers niets uit).<br />

1. Uitdaging 1: Laat zi<strong>en</strong> dat G ′′ isomorf is aan G.<br />

2. Uitdaging 2: Laat zi<strong>en</strong> dat G ′′ isomorf is aan G ′ .<br />

Als Speler 1 inderdaad de isomorfie tuss<strong>en</strong> G <strong>en</strong> G ′ k<strong>en</strong>t, dan kan zij aan beide uitdaging<strong>en</strong> voldo<strong>en</strong>. Als<br />

zij die niet k<strong>en</strong>t, dan kan zij aan hoogst<strong>en</strong>s één <strong>van</strong> beide voldo<strong>en</strong>. Bij random gekoz<strong>en</strong> uitdaging<strong>en</strong> valt zij<br />

dus met kans 0.5 door de mand. Door herhaling <strong>van</strong> het protocol kunn<strong>en</strong> we de kans op onontdekt bedrog<br />

zo klein mak<strong>en</strong> als we maar will<strong>en</strong>.<br />

E<strong>en</strong> geringe variatie op dit protocol geeft e<strong>en</strong> alternatief voor het eerder besprok<strong>en</strong> bit-commitm<strong>en</strong>t probleem<br />

(zie 4.6.2). In dit geval is het Speler 2 die de graf<strong>en</strong> G <strong>en</strong> G ′ maakt <strong>en</strong> Speler 1 produceert e<strong>en</strong> graaf<br />

G ′′ uit G als zij e<strong>en</strong> 0 wil vastlegg<strong>en</strong> <strong>en</strong> uit G ′ als zij e<strong>en</strong> 1 wil vastlegg<strong>en</strong>. Deze G ′′ wordt in hand<strong>en</strong> <strong>van</strong><br />

Speler 2 gegev<strong>en</strong>, die niet kan zi<strong>en</strong> <strong>van</strong> welke de graaf afkomstig is. Immers G, G ′ <strong>en</strong> G ′′ zijn alle isomorf.<br />

Als de tijd komt om het bit te lat<strong>en</strong> zi<strong>en</strong>, kan Speler 2 de isomorfie waarmee G ′′ is verkreg<strong>en</strong> prijsgev<strong>en</strong>. ✷<br />

7.6 IP=PSPACE<br />

Lange tijd is de vraag op<strong>en</strong> geblev<strong>en</strong> hoeveel computationele kracht er in e<strong>en</strong> interactief bewijs kan schuil<strong>en</strong>.<br />

Het is duidelijk dat voor alle problem<strong>en</strong> in NP korte interactieve bewijz<strong>en</strong> kunn<strong>en</strong> word<strong>en</strong> gegev<strong>en</strong>; deze klasse<br />

141


is ongeveer zo gedefinieerd. Aan de andere kant is PSPACE e<strong>en</strong> bov<strong>en</strong>gr<strong>en</strong>s voor de problem<strong>en</strong> waarvoor e<strong>en</strong><br />

interactief bewijs kan word<strong>en</strong> gegev<strong>en</strong>. Het standaardbewijs in de literatuur maakt gebruik <strong>van</strong> e<strong>en</strong> variant<br />

<strong>van</strong> backward inductie, maar er is e<strong>en</strong> simpeler manier om dit in te zi<strong>en</strong>. Eerst gev<strong>en</strong> we e<strong>en</strong> nette definitie<br />

<strong>van</strong> interactieve bewijz<strong>en</strong>.<br />

E<strong>en</strong> bewijzer P (voor ” prover”), mag elk berek<strong>en</strong>baar of onberek<strong>en</strong>baar mechanisme zijn, dat e<strong>en</strong> verzameling<br />

boodschapp<strong>en</strong> produceert waarop e<strong>en</strong> controleur V (voor ” verifier”) die polynomiale tijd begr<strong>en</strong>sd is,<br />

maar wel gebruik mag mak<strong>en</strong> <strong>van</strong> e<strong>en</strong> random g<strong>en</strong>erator kan reager<strong>en</strong> met boodschapp<strong>en</strong> voor de bewijzer.<br />

Gegev<strong>en</strong> één of andere invoer w (de te bewijz<strong>en</strong> stelling) bestaat interactie tuss<strong>en</strong> deze twee, P ↔ V , uit e<strong>en</strong><br />

serie boodschapp<strong>en</strong> m1, m2, . . . , m p(|w|) die als laatste boodschap ” accept” of ” reject” heeft. In het eerste<br />

geval noter<strong>en</strong> we P ↔ V = 1, <strong>en</strong> in het tweede geval P ↔ V = 0. Omdat V gebruik maakt <strong>van</strong> e<strong>en</strong> random<br />

g<strong>en</strong>erator, sprek<strong>en</strong> we eerder <strong>van</strong> P r(P ↔ V = 1), waarbij de waarschijnlijkheid uniform g<strong>en</strong>om<strong>en</strong> wordt<br />

over alle random strings met e<strong>en</strong> l<strong>en</strong>gte gelijk aan de l<strong>en</strong>gte <strong>van</strong> de berek<strong>en</strong>ing <strong>van</strong> V op invoer w. De<br />

boodschapp<strong>en</strong> met ev<strong>en</strong> index zijn afkomstig <strong>van</strong> de controleur, die met onev<strong>en</strong> index zijn afkomstig <strong>van</strong> de<br />

bewijzer.<br />

We zegg<strong>en</strong> dat e<strong>en</strong> taal L e<strong>en</strong> interactief bewijssysteem heeft, of tot de klasse IP hoort als <strong>en</strong> alle<strong>en</strong> als<br />

er e<strong>en</strong> polynomiale tijd begr<strong>en</strong>sde machine V bestaat zo dat geldt:<br />

1. w ∈ L ↔ (∃P )[P r(P ↔ V = accept) > 2/3]<br />

2. w /∈ L ⇔ (∀P )[P r(P ↔ V = 1) < 1/3].<br />

7.6.1 IP ⊆ PSPACE<br />

Volg<strong>en</strong>s de definitie kan de vraag of w geaccepteerd wordt, word<strong>en</strong> vertaald in e<strong>en</strong> vraag naar de maximum<br />

waarschijnlijkheid g<strong>en</strong>om<strong>en</strong> over alle mogelijke P . Als deze waarschijnlijkheid namelijk groter is dan 2/3 dan<br />

geldt w ∈ L, <strong>en</strong> als w /∈ L, dan is deze waarschijnlijkheid gegarandeerd kleiner dan 1/3. We lat<strong>en</strong> zi<strong>en</strong> dat<br />

gegev<strong>en</strong> w <strong>en</strong> V dit maximum door e<strong>en</strong> PSPACE machine kan word<strong>en</strong> berek<strong>en</strong>d. Aangezi<strong>en</strong> er ge<strong>en</strong> <strong>en</strong>kele<br />

begr<strong>en</strong>zing is aan de rek<strong>en</strong>kracht <strong>van</strong> P , is elke volgorde m1, m3, . . . , m p(|w|)−1 e<strong>en</strong> legale bewijzer. Het valt<br />

op dat de bewijzer dus eig<strong>en</strong>lijk helemaal niet naar het gezeur <strong>van</strong> de controleur hoeft te luister<strong>en</strong>.<br />

We moet<strong>en</strong> lat<strong>en</strong> zi<strong>en</strong> dat de vraag wat het maximum is over alle mogelijke bewijzers berek<strong>en</strong>d kan<br />

word<strong>en</strong> door e<strong>en</strong> machine met polynomiaal begr<strong>en</strong>sd geheug<strong>en</strong>. Hiertoe stell<strong>en</strong> wij ons e<strong>en</strong> berek<strong>en</strong>ingsboom<br />

voor met knop<strong>en</strong> waarin de Bewijzer <strong>en</strong> de Controleur afwissel<strong>en</strong>d aan de beurt zijn. In de blader<strong>en</strong> <strong>van</strong><br />

de boom is de Controleur aan de beurt <strong>en</strong> moet zij, op grond <strong>van</strong> de conversatie die gevormd wordt door<br />

de uitgewisselde boodschapp<strong>en</strong> op het pad dat in dit blad eindigt het bewijs accepter<strong>en</strong> of verwerp<strong>en</strong>. Als<br />

zij het bewijs accepteert, dan krijgt deze knoop de waarde 1, anders krijgt deze knoop de waarde 0. In<br />

alle andere knop<strong>en</strong> mak<strong>en</strong> we de volg<strong>en</strong>de berek<strong>en</strong>ing. Als de Bewijzer aan de beurt is, dan moet<strong>en</strong> we<br />

e<strong>en</strong> maximum nem<strong>en</strong> over alle mogelijke boodschapp<strong>en</strong> die de Bewijzer als antwoord op de conversatie op<br />

het bov<strong>en</strong>ligg<strong>en</strong>de pad kan gev<strong>en</strong>, we noter<strong>en</strong> dus hier het maximum <strong>van</strong> alle onderligg<strong>en</strong>de knop<strong>en</strong> die e<strong>en</strong><br />

waarde hebb<strong>en</strong> gekreg<strong>en</strong>. Als de Controleur aan de beurt is, dan moet<strong>en</strong> we e<strong>en</strong> (gewog<strong>en</strong>) gemiddelde<br />

nem<strong>en</strong> over de waard<strong>en</strong> in de onderligg<strong>en</strong>de knop<strong>en</strong>.<br />

Dat deze boom in PSPACE uit te rek<strong>en</strong><strong>en</strong> is, hoeft weinig betoog. Er zijn slechts polynomiaal veel<br />

boodschapp<strong>en</strong> in e<strong>en</strong> conversatie, <strong>en</strong> iedere boodschap heeft zelf slechts polynomiale l<strong>en</strong>gte. De recursiediepte<br />

<strong>van</strong> e<strong>en</strong> opgebouwde boom is dus slechts polynomiaal. Verder hoeft nooit meer dan één <strong>en</strong>kel pad <strong>van</strong> de<br />

boom in zijn geheel gexpandeerd te word<strong>en</strong>, want zowel het nem<strong>en</strong> <strong>van</strong> het maximum, als het nem<strong>en</strong> <strong>van</strong><br />

e<strong>en</strong> (gewog<strong>en</strong>) gemiddelde eist niet dat tuss<strong>en</strong>resultat<strong>en</strong> word<strong>en</strong> onthoud<strong>en</strong>. De boom kan dus gewoon <strong>van</strong><br />

links naar rechts recursief doorlop<strong>en</strong> word<strong>en</strong>, waarbij telk<strong>en</strong>s slechts één pad in het geheug<strong>en</strong> is opgeslag<strong>en</strong>.<br />

7.6.2 PSPACE ⊆ IP<br />

Voor dit deel <strong>van</strong> het bewijs lat<strong>en</strong> we zi<strong>en</strong> dat e<strong>en</strong> bek<strong>en</strong>d PSPACE-volledig probleem namelijk Quantified<br />

Boolean Formulas e<strong>en</strong> interactief bewijs heeft. We gebruik<strong>en</strong> hiervoor de arithmetische versie <strong>van</strong> e<strong>en</strong> formule.<br />

De waarheidswaard<strong>en</strong> voor e<strong>en</strong> logische variabele x, kunn<strong>en</strong> we ver<strong>van</strong>g<strong>en</strong> door e<strong>en</strong> waarde uit {0, 1}<br />

waarbij 0 de rol <strong>van</strong> FALSE speelt, <strong>en</strong> 1 de rol <strong>van</strong> TRUE. Neem logische formules φ <strong>en</strong> ψ <strong>en</strong> noem hun<br />

142


herleiding tot 0 <strong>en</strong> 1 door het invull<strong>en</strong> <strong>van</strong> de variabel<strong>en</strong> respectievelijk Φ <strong>en</strong> Ψ. Hoe dat moet als φ <strong>en</strong> ψ<br />

uit individuele variabel<strong>en</strong> bestaan hebb<strong>en</strong> we zojuist gezi<strong>en</strong>. Inductief herleid<strong>en</strong> we nu φ ∧ ψ <strong>en</strong> φ ∨ ψ tot 0<br />

<strong>en</strong> 1 door respectievelijk Φ × Ψ <strong>en</strong> Φ + Ψ − Φ × Ψ te nem<strong>en</strong>. Noem de waarde die je krijgt uit e<strong>en</strong> formule<br />

φ met één variabele x die je krijgt door x = i in te vull<strong>en</strong> Φ(i), dan is ∀xΦ(x) hetzelfde als Φ(0) × Φ(1) <strong>en</strong><br />

∃xΦ(x) hetzelfde asl Φ(0) + Φ(1) − Φ(0) × Φ(1).<br />

We merk<strong>en</strong> terloops op dat de term Φ(0) × Φ(1) eig<strong>en</strong>lijk wel kan word<strong>en</strong> weggelat<strong>en</strong>. We krijg<strong>en</strong> dan<br />

bij e<strong>en</strong> ware formule e<strong>en</strong> waarde groter dan 0 <strong>en</strong> bij e<strong>en</strong> onware formule de waarde 0 krijgt.<br />

E<strong>en</strong> quantified boolean formula kan nu op deze manier in zijn geheel vertaald word<strong>en</strong> naar e<strong>en</strong> getal dat<br />

groter dan 0 is dan <strong>en</strong> slechts dan als deze formule waar is. Neem eerst k e<strong>en</strong> vast getal <strong>en</strong> stel dat we<br />

e<strong>en</strong> formule hebb<strong>en</strong> met k variabel<strong>en</strong>, waarbij we de eerste variabele xk onbepaald lat<strong>en</strong> <strong>en</strong> we de overige<br />

variabel<strong>en</strong> invull<strong>en</strong> kortom, we nem<strong>en</strong> in plaats <strong>van</strong> de formule<br />

De formule<br />

P = QkxnQk−1xk−1 . . . Q1x1F (x1, . . . , xk)<br />

Qk−1xk−1 . . . Q1x1F (x1, . . . , xk)<br />

Met inductie <strong>en</strong> de vertaling hierbov<strong>en</strong> zi<strong>en</strong> we dat dit e<strong>en</strong> polynoom pk is <strong>van</strong> de graad 2 k . Bov<strong>en</strong>di<strong>en</strong> geldt in<br />

het geval Qk = ∃ dat pk(0)+pk(1) > 0 ↔ P = true <strong>en</strong> in het geval Qk = ∀ dat pk(0)+pk(1) > 0 ↔ P = true<br />

Twee verschill<strong>en</strong>de polynom<strong>en</strong> <strong>van</strong> de graad 2 k hebb<strong>en</strong> ” slechts” 2 k punt<strong>en</strong> geme<strong>en</strong>. Stel er geldt bijvoorbeeld<br />

niet pk(0) + pk(1) = 1, maar er is e<strong>en</strong> ander polynoom q waarvoor wel geldt dat q(0) + q(1) = 1<br />

wanneer we e<strong>en</strong> willekeurig getal r uit {1, . . . , n} kiez<strong>en</strong>, dan is de kans dat pk(r) = q(r) gelijk aan 2 k /n.<br />

Het getal r zou namelijk precies de x <strong>van</strong> e<strong>en</strong> snijpunt moet<strong>en</strong> zijn om dit waar te mak<strong>en</strong>.<br />

De Bewijzer <strong>en</strong> de Controleur spel<strong>en</strong> nu het volg<strong>en</strong>de spel—we nem<strong>en</strong> ev<strong>en</strong> +× als operator die e<strong>en</strong> + is<br />

in geval <strong>van</strong> ∃ <strong>en</strong> e<strong>en</strong> × in geval <strong>van</strong> ∀. De bewijzer wordt steeds gevraagd e<strong>en</strong> polynoom te lever<strong>en</strong> dat<br />

overe<strong>en</strong>komt met de quantified boolean formula als de volg<strong>en</strong>de quantor <strong>van</strong> de formule wordt afgehaald,<br />

noem het polynoom pk voor ronde k. In de eerste ronde controleert de controleur alle<strong>en</strong> dat p1(0) +× pk(1)<br />

In volg<strong>en</strong>de rondes is er e<strong>en</strong> extra controle beschikbaar, doordat de controleur in elke ronde e<strong>en</strong> random<br />

getal rk kiest, dat doorgeeft aan de Bewijzer, die pk(rk) uitrek<strong>en</strong>t. In de volg<strong>en</strong>de ronde moet de bewijzer<br />

dan steeds e<strong>en</strong> polynoom pk+i kiez<strong>en</strong> waarvoor geld pk+i(0) +× pk+i(1) = pk+i−1(rk+i−1.<br />

Met dit protocol bereik je twee ding<strong>en</strong>. Als de waarde <strong>van</strong> de quantified boolean formula werkelijk positief<br />

is (i.e., de formule is waar), dan kan de Bewijzer beginn<strong>en</strong> met het juiste polynoom <strong>en</strong> daarbij blijv<strong>en</strong>. Als<br />

alle kwantor<strong>en</strong> zijn geweest <strong>en</strong> alle waard<strong>en</strong> ingevuld, zijn Bewijzer <strong>en</strong> Controleur het erover e<strong>en</strong>s dat de<br />

waarde <strong>van</strong> het polynoom positief is (<strong>en</strong> dus de formule waar).<br />

Als de waarde <strong>van</strong> het polynoom 0 is <strong>en</strong> de Bewijzer produceert in de eerste ronde e<strong>en</strong> polynoom dat<br />

e<strong>en</strong> positieve waarde geeft bij het invull<strong>en</strong> <strong>van</strong> 0 <strong>en</strong> 1, dan moet erg<strong>en</strong>s onderweg naar het echte polynoom<br />

word<strong>en</strong> ” overgestapt”. Dat betek<strong>en</strong>t dat erg<strong>en</strong>s de polynom<strong>en</strong> pi <strong>en</strong> pi+1 precies in ri moet<strong>en</strong> snijd<strong>en</strong>. Als<br />

we de verzameling random getall<strong>en</strong> groot g<strong>en</strong>oeg kiez<strong>en</strong> is de kans daarop klein.<br />

De graad <strong>van</strong> het polynoom is wat aan de hoge kant. Om de bewering PSPACE ⊆ IP te bewijz<strong>en</strong>, zoud<strong>en</strong><br />

we graag ongeveer n quantor<strong>en</strong> in de boolean formula will<strong>en</strong> hebb<strong>en</strong>, waarmee de graad <strong>van</strong> het polynoom<br />

op 2 n uitkomt, anders kunn<strong>en</strong> we slechts formules met e<strong>en</strong> beperkt aantal quantor<strong>en</strong> aan [LFKN90]. Dat de<br />

graad <strong>van</strong> het polynoom beperkt kan word<strong>en</strong> (zelfs tot ongeveer 3) is e<strong>en</strong> observatie die A. Shamir [Sha92]<br />

aan de theorie toevoegde. Dat betek<strong>en</strong>t, gezi<strong>en</strong> het feit dat er expon<strong>en</strong>tieel veel getall<strong>en</strong> zijn <strong>van</strong> polynomiale<br />

l<strong>en</strong>gte dat de kans dat e<strong>en</strong> lieg<strong>en</strong>de bewijzer halverwege het bewijs zou kunn<strong>en</strong> overstapp<strong>en</strong> op e<strong>en</strong> snijd<strong>en</strong>d<br />

polynoom expon<strong>en</strong>tieel klein wordt.<br />

Voorbeeld 7.6.1: Bekijk de (ware) quantified boolean formula<br />

De uitdrukking<br />

A = �<br />

B = (∀x1)[x1 ∨ (∃x2)(∀x3)[[x1 ∧ x2] ∨ x3]]<br />

z1∈{0,1}<br />

⎡<br />

⎣(1 − z1) + �<br />

�<br />

z2∈{0,1} z3∈{0,1}<br />

143<br />

⎤<br />

(z1.z2 + z3) ⎦


is de arithmetizering <strong>van</strong> B. De waarde <strong>van</strong> deze uitdrukking is 2. Als we de eerste quantor weglat<strong>en</strong>, krijg<strong>en</strong><br />

we de uitdrukking<br />

⎡<br />

A(z1) = ⎣(1 − z1) + �<br />

⎤<br />

�<br />

(z1.z2 + z3) ⎦<br />

z2∈{0,1} z3∈{0,1}<br />

Hierbij hoort het polynoom q(z1) = z 2 1 + 1. Als P dit polynoom produceert, dan kan V eerst controler<strong>en</strong><br />

dat inderdaad q(1) × q(0) = 2, conform de bewering. Zoud<strong>en</strong> we z1 = 3 invull<strong>en</strong>, dan krijg<strong>en</strong> we<br />

⎡<br />

A(3) = ⎣(1 − 3) + �<br />

⎤<br />

�<br />

(3z2 + z3) ⎦ ,<br />

z2∈{0,1} z3∈{0,1}<br />

met waarde 10. V heeft alle<strong>en</strong> q dus V vult in q(3) = 9 + 1 = 10. Hieruit kan V afleid<strong>en</strong> dat de uitdrukking<br />

� �<br />

z2∈{0,1} z3∈{0,1}<br />

de waarde 10 − (1 − 3) = 12 moet hebb<strong>en</strong>, <strong>en</strong> aan P vrag<strong>en</strong> het polynoom dat hoort bij<br />

A(z2) = �<br />

(3z2 + z3)<br />

te g<strong>en</strong>erer<strong>en</strong>. Dit polynoom is<br />

z3∈{0,1}<br />

q(z2) = 9z 2 2 + 3z2.<br />

V controleert eerst dat q(0) + q(1) = 12 <strong>en</strong> kiest dan bijvoorbeeld z2 = 2. Er moet nu geld<strong>en</strong> dat<br />

A = �<br />

(6 + z3) = q(2) = 42<br />

. Het polynoom dat P verstuurt is<br />

z3∈{0,1}<br />

q(z3) = z3 + 6,<br />

<strong>en</strong> V kan zi<strong>en</strong> dat q(0).q(1) = 6.7 = 42. T<strong>en</strong>slotte kiest V voor z3 = 5 <strong>en</strong> controleert dat<br />

A(z3 = 5) = (6 + 5) = 5 + 6 = q(5).<br />

144<br />


Bijlage A<br />

Begripp<strong>en</strong>lijst<br />

In dit deel herhal<strong>en</strong> we e<strong>en</strong> aantal begripp<strong>en</strong> uit de tekst met hun betek<strong>en</strong>is in alfabetische volgorde. Zo is<br />

het voor de lezer makkelijker om snel de betek<strong>en</strong>is <strong>van</strong> e<strong>en</strong> begrip in de in de tekst gehanteerde vorm terug<br />

te vind<strong>en</strong>. Voor de context kan dan gebruik gemaakt word<strong>en</strong> <strong>van</strong> de index.<br />

adversary argum<strong>en</strong>t. Bewijsmethode die wordt gebruikt om e<strong>en</strong> ondergr<strong>en</strong>s voor e<strong>en</strong> algoritme te bewijz<strong>en</strong>.<br />

De uitvoering <strong>van</strong> de algoritme wordt gezi<strong>en</strong> als e<strong>en</strong> spel, waarbij e<strong>en</strong> d<strong>en</strong>kbeeldige teg<strong>en</strong>stander zo<br />

ongunstig mogelijke zett<strong>en</strong> doet. Voorbeeld: het zoek<strong>en</strong> in e<strong>en</strong> ongesorteerde rij. De elem<strong>en</strong>t<strong>en</strong> <strong>van</strong> de<br />

rij word<strong>en</strong> aan de zoekalgoritme gepres<strong>en</strong>teerd in willekeurige volgorde, maar met het gezochte elem<strong>en</strong>t<br />

als laatste in de rij. Zo wordt bewez<strong>en</strong> dat deze zoekmethode altijd minst<strong>en</strong>s alle elem<strong>en</strong>t<strong>en</strong> <strong>van</strong> de rij<br />

langs moet alvor<strong>en</strong>s te kunn<strong>en</strong> constater<strong>en</strong> dat het gezochte elem<strong>en</strong>t niet aanwezig is.<br />

amortized complexity. Uitgesmeerde complexiteit. De complexiteit <strong>van</strong> e<strong>en</strong> ingewikkelde stap wordt verdeeld<br />

over voorgaande stapp<strong>en</strong> <strong>van</strong> mindere complexiteit.<br />

articulatiepunt. Knoop in de graaf waardoor alle pad<strong>en</strong> tuss<strong>en</strong> twee andere knop<strong>en</strong> gaan. Als deze knoop<br />

wordt verwijderd bestaat de rester<strong>en</strong>de graaf uit t<strong>en</strong>minste twee verbond<strong>en</strong> compon<strong>en</strong>t<strong>en</strong>. Slechte<br />

knop<strong>en</strong> om in e<strong>en</strong> communicati<strong>en</strong>etwerk te hebb<strong>en</strong>.<br />

bankmethode. E<strong>en</strong> methode om uitgesmeerde complexiteit te] berek<strong>en</strong><strong>en</strong>. Bij elke stap wordt zowel de echte<br />

complexiteit als e<strong>en</strong> “spaarbedrag” in rek<strong>en</strong>ing gebracht. Het spaarsaldo kan later opg<strong>en</strong>om<strong>en</strong> word<strong>en</strong><br />

om voor de duurdere stapp<strong>en</strong> te betal<strong>en</strong>.<br />

barometer. Spil <strong>van</strong> de berek<strong>en</strong>ing. E<strong>en</strong> instructie die minst<strong>en</strong>s net zo vaak uitgevoerd wordt als e<strong>en</strong> willekeurige<br />

andere instructie. De complexiteit <strong>van</strong> de algoritme wordt uitgedrukt in het aantal ker<strong>en</strong> dat<br />

deze instructie wordt uitevoerd.<br />

begr<strong>en</strong>sde betegeling.<br />

naam: BOUNDED TILING<br />

gegev<strong>en</strong>: E<strong>en</strong> vierkant met kleur<strong>en</strong> langs de rand <strong>en</strong> e<strong>en</strong> verzameling Tegeltyp<strong>en</strong><br />

gevraagd: Is het mogelijk het vierkant te betegel<strong>en</strong> met de gegev<strong>en</strong> tegeltyp<strong>en</strong> zo dat de kleur<strong>en</strong><br />

langs de rand<strong>en</strong> <strong>van</strong> de tegels pass<strong>en</strong><br />

NP-volledig probleem. Bewijs met Master reductie <strong>van</strong> Turing machine probleem.<br />

beslissingsalgoritme. Algoritme die op elke invoer e<strong>en</strong> ja of nee antwoord geeft.<br />

beslissingsprobleem. Probleem dat vraagt om e<strong>en</strong> ja of nee beslissing.<br />

Bit Commitm<strong>en</strong>t . Probleem uit de Cryptografie. De <strong>en</strong>e partij stuurt naar de andere partij één bit informatie.<br />

Hoewel de andere partij zonder extra informatie er niet achter kan kom<strong>en</strong> of dit bit 0 of 1 is,<br />

kan de z<strong>en</strong>d<strong>en</strong>de partij niet achteraf het bit dat verstuurd is verander<strong>en</strong>.<br />

145


lowfish. Cryptoalgoritme.<br />

boedelscheiding.<br />

naam: PARTITION<br />

gegev<strong>en</strong>: E<strong>en</strong> verzameling <strong>van</strong> n getall<strong>en</strong> {x1, . . . , xn}<br />

gevraagd: Is er e<strong>en</strong> indexverzameling I zodat �<br />

i∈I xi = �<br />

i /∈I xi<br />

NP-volledig probleem. Reductie <strong>van</strong> KNAPSACK.<br />

branch & bound. Methode om de explosieve groei <strong>van</strong> e<strong>en</strong> zoekboom te beperk<strong>en</strong>. In elke knoop <strong>van</strong> de<br />

gedeeltelijk ontwikkelde zoekboom wordt e<strong>en</strong> waarde uitgerek<strong>en</strong>d die het optimum voorstelt dat in de<br />

subboom <strong>van</strong> die knoop nog te bereik<strong>en</strong> is. De knoop met de beste waarde wordt gesplitst (branch).<br />

Als e<strong>en</strong> pad geheel ontwikkeld is, hoeft ge<strong>en</strong> <strong>en</strong>kele knoop die e<strong>en</strong> slechter optimum voorspelt dan de<br />

gevond<strong>en</strong> waarde verder te word<strong>en</strong> ontwikkeld (bound).<br />

breadth first search. Manier om e<strong>en</strong> zoekboom te doorlop<strong>en</strong> waarbij <strong>van</strong> elke knoop eerst alle knop<strong>en</strong> op<br />

gelijke diepte word<strong>en</strong> bezocht voordat verder in de boom gegaan wordt.<br />

Catalaans getal. Groot getal dat in veel combinatorische problem<strong>en</strong> opduikt. Het is vernoemd naar de<br />

Belgische wiskundige Eugène Charles Catalan (1814–1894) <strong>en</strong> kan geschrev<strong>en</strong> word<strong>en</strong> als<br />

�<br />

Cn = 1<br />

n+12n �<br />

n.<br />

chromatic number Aantal kleur<strong>en</strong> dat minimaal nodig is om e<strong>en</strong> graaf te kleur<strong>en</strong>, zodat ge<strong>en</strong> twee knop<strong>en</strong><br />

die aan dezelfde kant zitt<strong>en</strong> dezelfde kleur krijg<strong>en</strong>. NP-volledig probleem. Reductie <strong>van</strong> satisfiability.<br />

circuit. Gerichte Acyclische Graaf waarin elke knoop e<strong>en</strong> poort (<strong>en</strong>, of, niet) voorstelt.<br />

Circuit Value Problem . Probleem om gegev<strong>en</strong> e<strong>en</strong> invoer, de waard<strong>en</strong> <strong>van</strong> de knop<strong>en</strong> met ingraad 0 in e<strong>en</strong><br />

circuit, de uitvoer, de waard<strong>en</strong> <strong>van</strong> de knop<strong>en</strong> met uitgraad 0 te berek<strong>en</strong><strong>en</strong>. LOGSPACE volledig voor<br />

P , reductie <strong>van</strong> Turingmachineprobleem.<br />

Clique<br />

naam: Clique<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G = (V, E) <strong>en</strong> e<strong>en</strong> getal K<br />

gevraagd: Is er e<strong>en</strong> V ′ ⊆ V met |V ′ | ≥ K, zodat V ′ × V ′ ⊆ E<br />

complexiteitsanalyse. Analyse <strong>van</strong> de complexiteit <strong>van</strong> e<strong>en</strong> algoritme of e<strong>en</strong> probleem.<br />

complexiteitsklasse Verzameling problem<strong>en</strong> <strong>van</strong> ongeveer dezelfde complexiteit.<br />

complexiteitsmaat. Maat voor de complexiteit <strong>van</strong> e<strong>en</strong> algoritme of e<strong>en</strong> probleem. De meestgebruikte mat<strong>en</strong><br />

zijn tijd <strong>en</strong> geheug<strong>en</strong>. Er zijn echter aftelbaar veel verschill<strong>en</strong>de complexiteitsmat<strong>en</strong>.<br />

compon<strong>en</strong>t, verbond<strong>en</strong>. Ondergraaf <strong>van</strong> e<strong>en</strong> graaf G waarin tuss<strong>en</strong> elk tweetal knop<strong>en</strong> e<strong>en</strong> pad is.<br />

connectivity. Mate <strong>van</strong> verbond<strong>en</strong>heid <strong>van</strong> e<strong>en</strong> graaf, minimaal aantal knop<strong>en</strong> (node connectivity) of kant<strong>en</strong><br />

(edge connectivity) om <strong>van</strong> de graaf t<strong>en</strong>minste twee compon<strong>en</strong>t<strong>en</strong> te mak<strong>en</strong>.<br />

cut, min. Minimale doorsnijding <strong>van</strong> e<strong>en</strong> graaf (met capaciteitsfunctie).<br />

naam: MINCUT<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G = (V, E) met e<strong>en</strong> capaciteitsfunctie c : E ↦→ R.<br />

gevraagd: Verzameling knop<strong>en</strong> V ′ zo dat �<br />

e∈V ′ ×V −V ′ c(e) minimaal is. In stroomproblem<strong>en</strong> geldt<br />

dat de waarde <strong>van</strong> de minimale doorsnijding gelijk is aan de maximale stroom.<br />

146


cyckel. Rij punt<strong>en</strong> in e<strong>en</strong> graaf zodat tuss<strong>en</strong> twee ope<strong>en</strong>volg<strong>en</strong>de punt<strong>en</strong> e<strong>en</strong> kant aanwezig is, tev<strong>en</strong>s is er<br />

e<strong>en</strong> kant tuss<strong>en</strong> de laatste in de eerste knoop in de rij. Als de cykel ge<strong>en</strong> subcykels—deelrij die ook<br />

e<strong>en</strong> cykel is—heeft, noem<strong>en</strong> we de cykel <strong>en</strong>kelvoudig<br />

deelgraaf . ondergraaf. Deelverzameling <strong>van</strong> de verzameling knop<strong>en</strong> met alle kant<strong>en</strong> die tuss<strong>en</strong> deze knop<strong>en</strong><br />

aanwezig zijn.<br />

depth first search. Methode om e<strong>en</strong> zoekboom te doorlop<strong>en</strong> die in e<strong>en</strong> knoop eerst de uitgaande kant<strong>en</strong> uit<br />

die knoop kiest. Als dat ge<strong>en</strong> nieuwe knop<strong>en</strong> meer oplevert wordt met bactracking de rest <strong>van</strong> de graaf<br />

op dezelfde manier doorlop<strong>en</strong>.<br />

DES. Data Encryption Standard. Versleutelingsalgoritme <strong>van</strong> het private key type. Veelgebruikte methode<br />

waar uitwisseling <strong>van</strong> sleutels relatief goedkoop is.<br />

descriptieve complexiteit. Beschrijv<strong>en</strong>de complexiteit, of complexiteit <strong>van</strong> de beschrijving. Hoeveel informatie<br />

is nodig om e<strong>en</strong> bepaald object te producer<strong>en</strong>. Meestgebruikt voorbeeld: Kolmogorov complexiteit,<br />

grootte <strong>van</strong> het kleinste Turingmachine programma dat het object produceert.<br />

diagonalisatie. Bewijsmethode langs “de diagonaal”. Twee aftelbare verzameling<strong>en</strong>, bijvoorbeeld programma’s<br />

<strong>en</strong> invoer<strong>en</strong> word<strong>en</strong> langs de horizontale, resp. verticale as uitgezet. E<strong>en</strong> bewijs teg<strong>en</strong> het bestaan <strong>van</strong><br />

elem<strong>en</strong>t <strong>van</strong> de <strong>en</strong>e verzameling wordt op de diagonaal verkreg<strong>en</strong>, door op coordinaat (i, i) steeds het<br />

teg<strong>en</strong>overgestelde gedrag neer te schrijv<strong>en</strong>. Het vooronderstelde elem<strong>en</strong>t kan dan op ge<strong>en</strong> plaats op de<br />

horizontale lijn staan. Voorbeeld<strong>en</strong>:<br />

1. Overaftelbaarheid <strong>van</strong> de reële getall<strong>en</strong>. Schrijf e<strong>en</strong> vooronderstelde aftelling <strong>van</strong> de reële getall<strong>en</strong><br />

tuss<strong>en</strong> 0 <strong>en</strong> 1 als decimale ontwikkeling<strong>en</strong> langs de horizontale as, waarbij de decimal<strong>en</strong> langs de<br />

verticale as gezet word<strong>en</strong>. Op de diagonaal komt telk<strong>en</strong>s e<strong>en</strong> ander cijfer dan het cijfer in het<br />

desbetreff<strong>en</strong>de getal. Het resultaat is e<strong>en</strong> oneindige decimale ontwikkeling die niet in de rij staat.<br />

2. Onbeslisbaarheid <strong>van</strong> het Halting probleem. Schrijf langs de horizontale as alle Turingmachine<br />

programmas <strong>en</strong> langs de verticale as mogelijke invoer<strong>en</strong>. Op de diagonaal staat e<strong>en</strong> 0 als machine<br />

i op invoer i stopt, <strong>en</strong> e<strong>en</strong> 1 als machine i niet op invoer i stopt. De machine die niet in de rij<br />

kan voorkom<strong>en</strong> is de machine die niet op invoer i stopt als er e<strong>en</strong> 0 op plaats (i, i) staat <strong>en</strong> wel<br />

stopt als er e<strong>en</strong> 1 op plaats (i, i) staat.<br />

discrete Fourier transformatie. Methode om e<strong>en</strong> gegev<strong>en</strong> polynoom <strong>van</strong> graad n te vertal<strong>en</strong> in de m waard<strong>en</strong><br />

die dit polynoom aanneemt in de m-de machts éénheidswortels {e 2πij/m }j=0,...m−1.<br />

dubbelverbond<strong>en</strong> compon<strong>en</strong>t. Compon<strong>en</strong>t <strong>van</strong> e<strong>en</strong> gerichte graaf waarbij tuss<strong>en</strong> elk tweetal punt<strong>en</strong> a <strong>en</strong> b<br />

zowel e<strong>en</strong> pad <strong>van</strong> a naar b als e<strong>en</strong> pad <strong>van</strong> b naar a is.<br />

dynamisch programmer<strong>en</strong>. Algoritmeontwerp voor optimaliseringsproblem<strong>en</strong> dat gebruik maakt <strong>van</strong> tabell<strong>en</strong><br />

waarin optimale oplossing<strong>en</strong> voor deelproblem<strong>en</strong> staan. Deze optimale oplossing<strong>en</strong> kunn<strong>en</strong> word<strong>en</strong><br />

sam<strong>en</strong>gevoegd tot oplossing<strong>en</strong> voor grotere deelproblem<strong>en</strong>, zodat uiteindelijk de optimale oplossing<br />

voor het hele probleem gevond<strong>en</strong> kan word<strong>en</strong>.<br />

EDIT RAM . Random Access Machine die tekst<strong>en</strong> bewerkt. In één operatie kan e<strong>en</strong> EDIT RAM e<strong>en</strong> stuk<br />

tekst (die in het programma staat of in e<strong>en</strong> register is opgeborg<strong>en</strong>) ver<strong>van</strong>g<strong>en</strong> door e<strong>en</strong> ander stuk<br />

tekst in de hele invoer. Deze eig<strong>en</strong>schap maakt de EDIT RAM lid <strong>van</strong> de tweede machine klasse. Alles<br />

wat e<strong>en</strong> Turing machine in polynomiaal geheug<strong>en</strong> kan do<strong>en</strong>, kan de EDIT RAM in polynomiale tijd <strong>en</strong><br />

omgekeerd.<br />

ext<strong>en</strong>ted gcd. Vorm <strong>van</strong> de Euclidische algoritme waarbij als de gcd <strong>van</strong> de ingevoerde getall<strong>en</strong> a <strong>en</strong> b gelijk<br />

aan 1 is, de algoritme ook e<strong>en</strong> c teruggeeft, zodat ac mod b = 1. Het getal c is de multiplicatieve<br />

inverse <strong>van</strong> a.<br />

147


ELEMENTARY . Eerste subrecursieve tijdbegr<strong>en</strong>sde klasse die bek<strong>en</strong>d geslot<strong>en</strong> is onder nondeterminisme.<br />

Op invoer <strong>van</strong> l<strong>en</strong>gte n geldt e<strong>en</strong> tijdgr<strong>en</strong>s <strong>van</strong> 2 22···<br />

� �� �<br />

.<br />

n<br />

<strong>en</strong>tscheidungsprobleem. De vraag of er e<strong>en</strong> algoritme bestaat om de universele geldigheid <strong>van</strong> eerste orde<br />

uitsprak<strong>en</strong> te besliss<strong>en</strong>. Turing gaf hier e<strong>en</strong> negatief antwoord op.<br />

Euler path. Pad in e<strong>en</strong> graaf dat elke kant precies één keer bevat. Elke graaf waarin elke knoop e<strong>en</strong> ev<strong>en</strong><br />

graad heeft heeft zo’n pad, <strong>en</strong> alle<strong>en</strong> deze graf<strong>en</strong> hebb<strong>en</strong> zo’n pad.<br />

EXACTE OVERDEKKING.<br />

naam: EXACT COVER<br />

gegev<strong>en</strong>: E<strong>en</strong> universum U = {1, . . . , n} met deelverzameling<strong>en</strong> Sj<br />

gevraagd: Bestaat er e<strong>en</strong> selectie deelverzameling<strong>en</strong> die sam<strong>en</strong> nog steeds e<strong>en</strong> overdekking zijn,<br />

maar paarsgewijs e<strong>en</strong> lege doorsnede hebb<strong>en</strong>?<br />

Het probleem of e<strong>en</strong> collectie deelverzameling<strong>en</strong> e<strong>en</strong> exacte overdekking hebb<strong>en</strong> is NP-volledig. Reductie<br />

<strong>van</strong> Begr<strong>en</strong>sde Betegeling<strong>en</strong>.<br />

EXP. Klasse <strong>van</strong> problem<strong>en</strong> waarvoor e<strong>en</strong> deterministische expon<strong>en</strong>tiële tijd begr<strong>en</strong>sde algoritme bestaat.<br />

Feedback vertex set.<br />

naam: FEEDBACK VERTEX SET<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G = (V, E) <strong>en</strong> e<strong>en</strong> getal K<br />

gevraagd: Bestaat er e<strong>en</strong> V ′ met |V ′ | ≤ K zodat elke cykel in G t<strong>en</strong>minste één knoop uit V ′ heeft.<br />

NP-volledig probleem. Reductie <strong>van</strong> VERTEX COVER<br />

Ford-Fulkerson algoritme. Methode om e<strong>en</strong> maximale stroom in e<strong>en</strong> netwerk te vind<strong>en</strong> die gebruik maakt<br />

<strong>van</strong> het herhaald id<strong>en</strong>tificer<strong>en</strong> <strong>van</strong> stroomvergrot<strong>en</strong>de pad<strong>en</strong>. De algoritme is correct, maar convergeert<br />

niet altijd.<br />

geheug<strong>en</strong>complexiteit. <strong>Complexiteit</strong>smaat die de hoeveelheid geheug<strong>en</strong> begr<strong>en</strong>st. De e<strong>en</strong>heid <strong>van</strong> geheug<strong>en</strong><br />

verschilt <strong>van</strong> model tot model. Voor e<strong>en</strong> Turingmachine is dat één bandcel, voor e<strong>en</strong> Random Access<br />

machine één register. De sequ<strong>en</strong>tial computation thesis eist dat redelijke machinemodell<strong>en</strong> elkaar in<br />

constante factor overhead in geheug<strong>en</strong> simuler<strong>en</strong>. Dit vergt soms e<strong>en</strong> andere manier om geheug<strong>en</strong>gebruik<br />

toe te rek<strong>en</strong><strong>en</strong>.<br />

geography, g<strong>en</strong>eralized. Spel waarbij de spelers om beurt<strong>en</strong> e<strong>en</strong> knoop mog<strong>en</strong> selecter<strong>en</strong> <strong>van</strong> e<strong>en</strong> gerichte<br />

graaf <strong>en</strong> die in hun verzameling op te nem<strong>en</strong>. De geselecteerde knoop moet altijd e<strong>en</strong> opvolger zijn <strong>van</strong><br />

de door de andere speler gekoz<strong>en</strong> knop<strong>en</strong>. De vraag is of de beginn<strong>en</strong>de speler e<strong>en</strong> winn<strong>en</strong>de strategie<br />

heeft in e<strong>en</strong> gegev<strong>en</strong> graaf. NP-volledig probleem. Reductie <strong>van</strong> QBF.<br />

graaf . Verzameling knop<strong>en</strong> <strong>en</strong> kant<strong>en</strong>. De kant<strong>en</strong> zijn ongeord<strong>en</strong>de par<strong>en</strong> knop<strong>en</strong>. De knop<strong>en</strong> word<strong>en</strong> ook<br />

wel punt<strong>en</strong> g<strong>en</strong>oemd. De kant<strong>en</strong> word<strong>en</strong> in gerichte graf<strong>en</strong> ook wel bog<strong>en</strong> g<strong>en</strong>oemd. In gerichte graf<strong>en</strong><br />

zijn de bog<strong>en</strong> geord<strong>en</strong>de par<strong>en</strong> punt<strong>en</strong>.<br />

greedy algorithm (hier gulizge algoritme). Optimaliseringsalgoritme waarbij in elke stap e<strong>en</strong> zo gunstig mogelijke<br />

keuze gemaakt wordt. Op e<strong>en</strong> keuze wordt nooit teruggekom<strong>en</strong>. De problem<strong>en</strong> waarvoor met<br />

gulzige algoritm<strong>en</strong> e<strong>en</strong> optimale oplossing gevond<strong>en</strong> kan word<strong>en</strong> zijn <strong>van</strong> e<strong>en</strong> speciale soort. Bek<strong>en</strong>d<br />

voorbeeld is de kortste pad algoritme <strong>van</strong> Dijkstra.<br />

HALT . Het Halting probleem voor Turing machines. Gegev<strong>en</strong> e<strong>en</strong> paar x, y waarbij x e<strong>en</strong> Turingmachineprogramma<br />

is <strong>en</strong> y e<strong>en</strong> invoer. Zal x op invoer y stopp<strong>en</strong>. Het probleem is onbeslisbaar. Dwz er is<br />

ge<strong>en</strong> Turingmachineprogramma dat voor elk paar x, y stopt <strong>en</strong> ja zegt als x op y stopt <strong>en</strong> nee anders.<br />

Hamilton circuit.<br />

148


naam: HAMILTON CIRCUIT<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G.<br />

gevraagd: Vormt e<strong>en</strong> deel <strong>van</strong> de kant<strong>en</strong> <strong>van</strong> G e<strong>en</strong> <strong>en</strong>kelvoudige cykel langs alle knop<strong>en</strong>?<br />

NP-volledig. Reductie <strong>van</strong> VERTEX COVER.<br />

handelsreiziger probleem.<br />

naam: TSP<br />

gegev<strong>en</strong>: E<strong>en</strong> volledige gerichte graaf G met e<strong>en</strong> gewichtsfunctie op de kant<strong>en</strong> <strong>en</strong> e<strong>en</strong> gr<strong>en</strong>s b.<br />

gevraagd: Bestaat er e<strong>en</strong> <strong>en</strong>kelvoudige cykel in G waar<strong>van</strong> het totale gewicht kleiner is dan b?<br />

NP-volledig. Reductie <strong>van</strong> HAMILTON CIRCUIT.<br />

hashtabel. Database met natuurlijke getall<strong>en</strong> als index. De plaats <strong>van</strong> e<strong>en</strong> record in de database wordt<br />

bepaald door e<strong>en</strong> zog<strong>en</strong>oemde hashfunctie die op grond <strong>van</strong> e<strong>en</strong> veld in het record e<strong>en</strong> waarde berek<strong>en</strong>d.<br />

Doorgaans is deze functie cyclish <strong>en</strong> berek<strong>en</strong>t hij niet e<strong>en</strong> unieke waarde voor elk record. Als twee<br />

records hetzelfde adres wordt toegewez<strong>en</strong> ontstaat e<strong>en</strong> collision die op verschill<strong>en</strong>de manier<strong>en</strong> kan<br />

word<strong>en</strong> opgelost (collision resolution).<br />

heuristiek. Op natte vingerwerk gebaseerde methode om keuz<strong>en</strong> te mak<strong>en</strong> in optimaliseringsproblem<strong>en</strong>. Vaak<br />

di<strong>en</strong>t e<strong>en</strong>—niet werk<strong>en</strong>de—greedy algoritme als heuristiek voor e<strong>en</strong> optimaliseringsprobleem waarna<br />

suboptimale oplossing<strong>en</strong> word<strong>en</strong> verbeterd door bactracking of local search.<br />

HITTING SET .<br />

naam: HITTING SET<br />

gegev<strong>en</strong>: E<strong>en</strong> verzameling deelverzameling<strong>en</strong> {Sj}j <strong>van</strong> U = {1, . . . , n} <strong>en</strong> e<strong>en</strong> getal k<br />

gevraagd: Is er e<strong>en</strong> deelverzameling V ⊆ U met |V | ≤ k, zodat voor alle j geldt §j ∩ V �= ∅?<br />

NP-volledig, reductie <strong>van</strong> VERTEX COVER<br />

INDEPENDENT SET .<br />

naam: INDEPENDENT SET<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G = (V, E) <strong>en</strong> e<strong>en</strong> getal K<br />

gevraagd: Is er e<strong>en</strong> deelverzameling V ′ ⊆ V met |V ′ | ≤ K zdd V ′ × V ′ ∩ E = ∅?<br />

inproduct Getal dat verkreg<strong>en</strong> wordt door <strong>van</strong> twee vector<strong>en</strong> v <strong>en</strong> w, beide <strong>van</strong> dim<strong>en</strong>sie n, overe<strong>en</strong>komstige<br />

coordinat<strong>en</strong> met elkaar te verm<strong>en</strong>igvuldig<strong>en</strong> <strong>en</strong> het resultaat <strong>van</strong> de verm<strong>en</strong>igvuldiging<strong>en</strong> bij elkaar op<br />

te tell<strong>en</strong>. Als het inproduct <strong>van</strong> v <strong>en</strong> w gelijk is aan 0, dan staan v <strong>en</strong> w loodrecht op elkaar.<br />

integraalk<strong>en</strong>merk <strong>van</strong> d’Alembert K<strong>en</strong>merk dat gebruikt wordt om de som <strong>van</strong> e<strong>en</strong> reeks af te schatt<strong>en</strong>. De<br />

som is altijd kleiner of groter dan de integraal <strong>van</strong> de functie, afhankelijk <strong>van</strong> welke gr<strong>en</strong>z<strong>en</strong> word<strong>en</strong><br />

g<strong>en</strong>om<strong>en</strong>.<br />

Khacian’s algoritme. Algoritme voor lineaire programmer<strong>en</strong>. De meest gebruikte algoritme, de simplex algoritme<br />

is in sommige gevall<strong>en</strong> expon<strong>en</strong>tieel. Khacian’s algoritme, ook wel ellipsoide algoritme g<strong>en</strong>oemd,<br />

is altijd polynomiaal.<br />

kleurbaarheid. De vraag of e<strong>en</strong> graaf zodanig met e<strong>en</strong> gegev<strong>en</strong> aantal kleur<strong>en</strong> te kleur<strong>en</strong> is dat ge<strong>en</strong> twee<br />

punt<strong>en</strong> die door e<strong>en</strong> kant verbond<strong>en</strong> zijn dezelfde kleur krijg<strong>en</strong>. 2-kleurbaarheid is polynomiaal, 3kleurbaarheid<br />

is NP-volledig (reductie <strong>van</strong> 3SAT). 4-kleurbaarheid <strong>van</strong> planaire graf<strong>en</strong> is triviaal. 3kleurbaarheid<br />

is ook voor planaire graf<strong>en</strong> NP-volledig.<br />

kleurgetal. Minimale aantal kleur<strong>en</strong> dat nodig is om e<strong>en</strong> gegev<strong>en</strong> graaf te kleur<strong>en</strong>. Ook wel CHROMATIC<br />

NUMBER g<strong>en</strong>oemd.<br />

KNAPSACK .<br />

149


naam: KNAPSACK<br />

gegev<strong>en</strong>: E<strong>en</strong> verzameling object<strong>en</strong> o1, . . . , on met gewicht<strong>en</strong> w1, . . . , wn <strong>en</strong> waard<strong>en</strong> v1, . . . , vn <strong>en</strong><br />

twee getall<strong>en</strong> b <strong>en</strong> v.<br />

gevraagd: Bestaat er e<strong>en</strong> verzameling I, zo dat �<br />

i∈I wi ≤ b, terwijl �<br />

i∈I vi ≥ v?<br />

knoopoverdekking, VERTEX COVER.<br />

naam: VERTEX COVER<br />

gegev<strong>en</strong>: E<strong>en</strong> graaf G = (V, E) <strong>en</strong> e<strong>en</strong> getal K.<br />

gevraagd: Bestaat er e<strong>en</strong> V ′ ⊆ V met |V ′ | ≤ K zdd (∀e ∈ E)[e ∩ V ′ �= ∅]?<br />

knowledge, zero. Type protocol waarbij de Verifier overtuigd raakt <strong>van</strong> de juistheid <strong>van</strong> de stelling terwijl<br />

niets wordt geleerd over het bewijs.<br />

Kruskal, algoritme <strong>van</strong>. Methode om e<strong>en</strong> mincost spanning tree te berek<strong>en</strong><strong>en</strong> in e<strong>en</strong> gewog<strong>en</strong> graaf. Bij deze<br />

algoritme word<strong>en</strong> e<strong>en</strong> aantal bom<strong>en</strong> gevormd die sam<strong>en</strong>groei<strong>en</strong> totdat er nog één boom over is.<br />

LOGSPACE. Klasse <strong>van</strong> tal<strong>en</strong> die kan word<strong>en</strong> herk<strong>en</strong>d door e<strong>en</strong> Turing machine waar<strong>van</strong> het geheug<strong>en</strong>gebruik<br />

wordt begr<strong>en</strong>sd door de logaritme <strong>van</strong> de l<strong>en</strong>gte <strong>van</strong> de invoer.<br />

machtreeks. Reeks waarbij de term<strong>en</strong> macht<strong>en</strong> <strong>van</strong> e<strong>en</strong> grondtal zijn.<br />

masterprobleem. Probleem dat volledig wordt bewez<strong>en</strong> in e<strong>en</strong> klasse door e<strong>en</strong> reductieschema te gev<strong>en</strong> waarbij<br />

e<strong>en</strong> Turing machine, e<strong>en</strong> gr<strong>en</strong>s <strong>en</strong> e<strong>en</strong> invoer de parameters zijn.<br />

masterreductie. Reductieschema voor het volledig bewijz<strong>en</strong> <strong>van</strong> e<strong>en</strong> masterprobleem.<br />

matching, perfect Selectie <strong>van</strong> e<strong>en</strong> aantal kant<strong>en</strong> <strong>van</strong> e<strong>en</strong> graaf waarbij de graaf beperkt tot deze kant<strong>en</strong><br />

twee (of meer) delig wordt.<br />

matrixverm<strong>en</strong>igvuldigingsexpon<strong>en</strong><strong>en</strong>t. Expon<strong>en</strong>t <strong>van</strong> het polynoom dat de gr<strong>en</strong>s is voor de meest effici<strong>en</strong>te<br />

matrixverminigvuldigingsalgoritme.<br />

minor. Ondergraaf die uit e<strong>en</strong> graaf G kan word<strong>en</strong> verkreg<strong>en</strong> door e<strong>en</strong> kant weg te lat<strong>en</strong> of sam<strong>en</strong> te trekk<strong>en</strong>.<br />

MRAM . Multiplication RAM. Random Access machine waarbij de kost<strong>en</strong> <strong>van</strong> e<strong>en</strong> verm<strong>en</strong>igvuldiging <strong>van</strong><br />

willekeurig grote operand<strong>en</strong> op 1 wordt gesteld.<br />

NP Klasse <strong>van</strong> problem<strong>en</strong> herk<strong>en</strong>baar door nondeterministische Turingmachines in polynomiale tijd. Equival<strong>en</strong>t:<br />

de klasse <strong>van</strong> problem<strong>en</strong> waarvoor e<strong>en</strong> gegev<strong>en</strong> oplossing in polynomiale tijd kan word<strong>en</strong> gecontroleerd.<br />

ODDMINSAT . naam: ODDMINSAT<br />

gegev<strong>en</strong>: E<strong>en</strong> formule F = F (x1, . . . , xn).<br />

gevraagd: Is het laatste bit <strong>van</strong> de lexicografisch kleinste vervulling, gelez<strong>en</strong> als bitstring, gelijk<br />

aan 1?<br />

Volledig voor P NP , het eerste Delta level <strong>van</strong> de polynomiale hierarchie [Sto76].<br />

ondergraaf . Graaf die verkreg<strong>en</strong> wordt uit e<strong>en</strong> graaf G door e<strong>en</strong> aantal punt<strong>en</strong> met de bijbehor<strong>en</strong>de incid<strong>en</strong>te<br />

kant<strong>en</strong> weg te lat<strong>en</strong>.<br />

ondergr<strong>en</strong>s. Minimaal b<strong>en</strong>odigde looptijd voor e<strong>en</strong> algoritme op invoer<strong>en</strong> <strong>van</strong> l<strong>en</strong>gte n, waarbij over alle<br />

invoer<strong>en</strong> <strong>van</strong> l<strong>en</strong>gt n het maximum g<strong>en</strong>om<strong>en</strong> mag word<strong>en</strong>.<br />

opspann<strong>en</strong>de boom. Deel <strong>van</strong> de kant<strong>en</strong> <strong>van</strong> e<strong>en</strong> graaf dat e<strong>en</strong> boom vormt waarin alle punt<strong>en</strong> zijn opg<strong>en</strong>om<strong>en</strong>.<br />

optimalisatiealgoritme. Algoritme die de optimale oplossing vindt voor e<strong>en</strong> probleem.<br />

optimaliseringsprobleem. Probleem waarbij naar e<strong>en</strong> optimum gezocht wordt. Zie ook: beslissingsprobleem.<br />

150


overdekking. Selectie <strong>van</strong> deelverzameling<strong>en</strong> die sam<strong>en</strong> alle elem<strong>en</strong>t<strong>en</strong> <strong>van</strong> e<strong>en</strong> gegev<strong>en</strong> verzameling bevatt<strong>en</strong>.<br />

overdekkingsprobleem. Probleem dat het vind<strong>en</strong> <strong>van</strong> e<strong>en</strong> overdekking stelt.<br />

P. Klasse <strong>van</strong> problem<strong>en</strong> die zijn op te loss<strong>en</strong> met e<strong>en</strong> deterministische polynomiale tijd begr<strong>en</strong>sde Turing<br />

machine.<br />

padding lemma Lemma uit de recursietheorie. Bij elke codering <strong>van</strong> Turingmachines als natuurlijke getall<strong>en</strong>,<br />

komt elke Turingmachine die e<strong>en</strong> bepaalde functie berek<strong>en</strong>t oneindig vaak voor.<br />

parallellisme, onbegr<strong>en</strong>sd. Machinemodel waarbij verschill<strong>en</strong>de processor<strong>en</strong> tegelijkertijd werk<strong>en</strong>. Met onbegr<strong>en</strong>sd<br />

parallelle machines kunn<strong>en</strong> PSPACE volledige problem<strong>en</strong> in polynomiale tijd word<strong>en</strong> opgelost.<br />

perebor. Russisch woord dat de inher<strong>en</strong>te hardheid <strong>van</strong> combinatorische problem<strong>en</strong> karakterizeert.<br />

pot<strong>en</strong>tiaalmethode. Methode om de uitgesmeerde complexiteit <strong>van</strong> e<strong>en</strong> algoritme te bepal<strong>en</strong>.<br />

PRAM . Parallelle Random Access Machine. Machinemodel met onbegr<strong>en</strong>sd parallellisme, ook wel SIMD<br />

RAM g<strong>en</strong>oemd.<br />

priemfactor<strong>en</strong>. Factor<strong>en</strong> waardoor e<strong>en</strong> getal deelbaar is die zelf alle<strong>en</strong> deelbaar zijn door 1 <strong>en</strong> zichzelf.<br />

priemgetal. Getal dat alle<strong>en</strong> deelbaar is door 1 <strong>en</strong> zichzelf.<br />

primaliteitstest<br />

naam: PRIMALITY<br />

gegev<strong>en</strong>: E<strong>en</strong> getal p<br />

gevraagd: Is p priem<br />

. Probleem in P . Bewijs door Agrawal, Kayal <strong>en</strong> Sax<strong>en</strong>a [AKS04]. Lange tijd heeft m<strong>en</strong> gedacht<br />

dat dit e<strong>en</strong> probleem in NP ∩ Co − NP was dat niet in P zat, hoewel er goede randomized algoritm<strong>en</strong><br />

bestaan die de primaliteit <strong>van</strong> e<strong>en</strong> getal kunn<strong>en</strong> test<strong>en</strong>. Deze algoritm<strong>en</strong> word<strong>en</strong> in de praktijk nog<br />

steeds gebruikt.<br />

Prim, algoritme <strong>van</strong>. Methode om e<strong>en</strong> mincost spanning tree te berek<strong>en</strong><strong>en</strong> in e<strong>en</strong> gewog<strong>en</strong> graaf. Bij deze<br />

algoritme is er steeds één deel <strong>van</strong> e<strong>en</strong> opspann<strong>en</strong>de boom die langzaam groeit totdat alle punt<strong>en</strong> er<br />

deel <strong>van</strong> uitmak<strong>en</strong>.<br />

primaliteitstest. Test om te bepal<strong>en</strong> of e<strong>en</strong> getal e<strong>en</strong> priemgetal is.<br />

primitieve n-de machts éénheidswortel. Oplossing <strong>van</strong> de vergelijking x n − 1 = 0.<br />

probabilistische algoritm<strong>en</strong> <strong>Algoritm<strong>en</strong></strong> die gebruik mog<strong>en</strong> mak<strong>en</strong> <strong>van</strong> coinflips.<br />

PSPACE. Klasse <strong>van</strong> problem<strong>en</strong> oplosbaar door Turingmachines die in geheug<strong>en</strong> begr<strong>en</strong>sd zijn door e<strong>en</strong><br />

polynoom in de l<strong>en</strong>gte <strong>van</strong> de invoer.<br />

quantified boolean formulae. Predicaatlogische formules.<br />

quantum computing. Berek<strong>en</strong>ing<strong>en</strong> gebaseerd op principes <strong>van</strong> de quantummechanica. De invoer is e<strong>en</strong><br />

quantum state, meestal e<strong>en</strong> superpositie <strong>van</strong> toestand<strong>en</strong> die ontwikkelt door middel <strong>van</strong> unitaire afbeelding<strong>en</strong>.<br />

Gedur<strong>en</strong>de berek<strong>en</strong>ing<strong>en</strong> wordt de toestand e<strong>en</strong> aantal mal<strong>en</strong> geobserveerd, waardoor e<strong>en</strong><br />

gehele of gedeeltelijke collapse <strong>van</strong> de superpositie plaatsvindt.<br />

quicksort Sorteermethode volg<strong>en</strong>s het verdeel-<strong>en</strong>-heersprincipe. In e<strong>en</strong> rij <strong>van</strong> n elem<strong>en</strong>t<strong>en</strong> wordt e<strong>en</strong> spil<br />

gekoz<strong>en</strong>, waarna alle elem<strong>en</strong>t<strong>en</strong> kleiner dan de spil links <strong>van</strong> de spil geplaatst word<strong>en</strong>, terwijl alle andere<br />

elem<strong>en</strong>t<strong>en</strong> rechts <strong>van</strong> de spil geplaatst word<strong>en</strong>. De twee deelrij<strong>en</strong> word<strong>en</strong> recursief op dezelfde wijze<br />

gesorteerd.<br />

151


adix sort. Methode <strong>van</strong> sorter<strong>en</strong> gebaseerd op het achtere<strong>en</strong>volg<strong>en</strong>s sorter<strong>en</strong> <strong>van</strong> getall<strong>en</strong> op basis <strong>van</strong> de<br />

in die getall<strong>en</strong> voorkom<strong>en</strong>de cijfers.<br />

RAM . Random Access Machine. Machinemodel bestaande uit e<strong>en</strong> CPU die e<strong>en</strong> programma uitvoert dat uit<br />

e<strong>en</strong> g<strong>en</strong>ummerde lijst <strong>van</strong> instructies bestaat. Het geheug<strong>en</strong> <strong>van</strong> de machine is e<strong>en</strong> onbegr<strong>en</strong>sd aantal<br />

registers die elk e<strong>en</strong> natuurlijk getal kunn<strong>en</strong> bevatt<strong>en</strong>.<br />

recurr<strong>en</strong>te betrekking. Vergelijking die de verhouding weergeeft <strong>van</strong> geïndexeerde variabel<strong>en</strong>. In deze tekst<br />

word<strong>en</strong> recurr<strong>en</strong>te betrekking<strong>en</strong> vooral gebruikt voor de complexiteitsanalyse <strong>van</strong> recursieve algoritm<strong>en</strong>.<br />

reductie. Bewerking de de relatieve complexiteit <strong>van</strong> problem<strong>en</strong> bepaalt.<br />

RSA. Public key cryptosysteem vernoemd naar de uitvinders: Rivest, Shamir <strong>en</strong> Adleman.<br />

simplexalgoritme Methode om lineair programmer<strong>en</strong> problem<strong>en</strong> op te loss<strong>en</strong>. De afbeelding<strong>en</strong> lop<strong>en</strong> <strong>van</strong><br />

hoekpunt naar hoekpunt op e<strong>en</strong> polytoop om het optimum <strong>van</strong> de lineaire functie op dat polytoop te<br />

vind<strong>en</strong>.<br />

spil. Zie barometer.<br />

sleutel. Onderdeel <strong>van</strong> e<strong>en</strong> versleutelingsalgoritme. Met de sleutel is codering <strong>en</strong> decodering e<strong>en</strong>voudig.<br />

Zonder sleutel is het moeilijk.<br />

Strass<strong>en</strong>, algoritme <strong>van</strong>. Recursieve manier om vierkante matrices met elkaar te verm<strong>en</strong>igvuldig<strong>en</strong>. In<br />

plaats <strong>van</strong> O(n 3 ) heeft deze algoritme e<strong>en</strong> complexiteit O(n 2 log 7 .<br />

stroomvergrot<strong>en</strong>de pad<strong>en</strong> Pad<strong>en</strong> in e<strong>en</strong> netwerk waarlangs de capaciteit niet is uitgeput. Langs deze pad<strong>en</strong> is<br />

het vergrot<strong>en</strong> <strong>van</strong> de stroom nog mogelijk. Ess<strong>en</strong>tieel onderdeel in de Algoritme <strong>van</strong> Ford <strong>en</strong> Fulkerson.<br />

Turing machine. Machinemodel bestaande uit e<strong>en</strong> c<strong>en</strong>trale verwerkingse<strong>en</strong>heid <strong>en</strong> e<strong>en</strong> band. De Turingmachine<br />

werkt doordat in elke stap e<strong>en</strong> symbool <strong>van</strong> de band gelez<strong>en</strong> wordt, e<strong>en</strong> symbool op de band<br />

geschrev<strong>en</strong> wordt <strong>en</strong> de machine <strong>van</strong> de <strong>en</strong>e toestand uit e<strong>en</strong> eindige verzameling toestand<strong>en</strong> naar e<strong>en</strong><br />

andere toestand overgaat. T<strong>en</strong>slotte beweegt de leeskop op de band naar links of naar rechts.<br />

toestandsovergangsfunctie Functie (soms relatie) die op invoer e<strong>en</strong> toestand <strong>en</strong> e<strong>en</strong> symbool, de volg<strong>en</strong>de<br />

toestand(<strong>en</strong>) geeft <strong>en</strong> het symbool of de symbol<strong>en</strong> die het gelez<strong>en</strong> symbool gaan ver<strong>van</strong>g<strong>en</strong>, alsmede<br />

de beweging <strong>van</strong> de leeskop.<br />

versleutelingsalgoritme Algoritme die gegev<strong>en</strong> e<strong>en</strong> sleutel e<strong>en</strong> boodschap codeert.<br />

vierkleur<strong>en</strong>probleem Is het mogelijk e<strong>en</strong> gegev<strong>en</strong> planaire graaf met vier kleur<strong>en</strong> te kleur<strong>en</strong>, zodat ge<strong>en</strong> twee<br />

met elkaar verbond<strong>en</strong> knop<strong>en</strong> dezelfde kleur krijg<strong>en</strong>. Antwoord: ja. Bewijs gevond<strong>en</strong> met behulp <strong>van</strong><br />

e<strong>en</strong> computer door Appel <strong>en</strong> Hak<strong>en</strong>. Naar e<strong>en</strong> inzichtelijk bewijs voor deze stelling wordt nog steeds<br />

druk gezocht.<br />

waarheidswaard<strong>en</strong> True <strong>en</strong> False of 1 <strong>en</strong> 0. Waard<strong>en</strong> die aan variabel<strong>en</strong> in e<strong>en</strong> propositie kunn<strong>en</strong> word<strong>en</strong><br />

toegek<strong>en</strong>d.<br />

zelfreduceerbaarheid Eig<strong>en</strong>schap <strong>van</strong> bepaalde problem<strong>en</strong>. Het antwoord op e<strong>en</strong> zelfreduceerbaar probleem<br />

kan word<strong>en</strong> gevond<strong>en</strong> door e<strong>en</strong> aantal kleinere instanties <strong>van</strong> hetzelfde probleem op te loss<strong>en</strong>. Zelfreduceerbare<br />

problem<strong>en</strong> zijn typisch problem<strong>en</strong> die met recursieve algoritm<strong>en</strong> kunn<strong>en</strong> word<strong>en</strong> aangepakt.<br />

zoekboom Boom die door e<strong>en</strong> zoekalgoritme wordt doorlop<strong>en</strong>. Typisch voorbeeld is e<strong>en</strong> access structuur in<br />

e<strong>en</strong> database.<br />

zoekruimte. Totaal <strong>van</strong> alle mogelijke elem<strong>en</strong>t<strong>en</strong> die door e<strong>en</strong> zoekalgoritme zoud<strong>en</strong> kunn<strong>en</strong> word<strong>en</strong> gevond<strong>en</strong>.<br />

De afmeting<strong>en</strong> <strong>van</strong> de zoekruimte zijn <strong>van</strong> groot belang voor de complexiteit <strong>van</strong> e<strong>en</strong> zoekalgoritme.<br />

152


Bibliografie<br />

[AB98] M. Akra and L. Bazzi. On the solution of linear recurr<strong>en</strong>ce equations. Computational Optimization<br />

and Applications, 10:195–210, 1998.<br />

[AH77a] K. Appel and W. Hak<strong>en</strong>. Every planar map is four colorable. part i. discharging. Illinois J.<br />

Math., 21:429–490, 1977.<br />

[AH77b] K. Appel and W. Hak<strong>en</strong>. Every planar map is four colorable. part ii. reducibility. Illinois J.<br />

Math., 21:491–567, 1977.<br />

[AKS04] Manindra Agrawal, Neeraj Kayal, and Nitin Sax<strong>en</strong>a. Primes is in P. Annals of Mathematics,<br />

160(2):781–793, 2004.<br />

[BB96] G. Brassard and P. Bratley. Fundam<strong>en</strong>tals of Algorithmics. Pr<strong>en</strong>tice Hall International Editions,<br />

1996.<br />

[Bur00] M. Buro. Simple amazons <strong>en</strong>dgames and their connection to hamilton circuits in cubic subgrid<br />

graphs. In Proc. 2nd Int. Conf. Computers and Games, 2000.<br />

[CDRH + 96] J. Cowie, B. Dodson, R.Elk<strong>en</strong>bracht-Huizing, A.K. L<strong>en</strong>stra, P.L. Montgomery, and J. Zayer.<br />

A world wide number field sieve factoring record: on to 512 bits. In Ad<strong>van</strong>ces in Cryptology–<br />

ASIACRYPT6, pages 382–394, 1996.<br />

[CFLS97] A. Condon, J. Feig<strong>en</strong>baum, C. Lund, and P. Shor. Random debaters and the hardness of<br />

approximating stochastic functions. SIAM Journal on Computing, 26(2):369–400, 1997.<br />

[CLR90] T.H. Corm<strong>en</strong>, C.E. Leiserson, and R.L. Rivest. Introduction to Algorithms. MIT Press, 1990.<br />

[CSS97] G. Cornell, J.H. Silverman, and G. Stev<strong>en</strong>s, editors. Modular Forms and Fermat’s Last Theorem.<br />

Springer-Verlag, 1997.<br />

[Cul99] J. Culberson. Sokoban is pspace-complete. In Int. Conf. Fun with Algorithms, Proceedings in<br />

Informatics 4, pages 65–76, 1999.<br />

[DH76] W. Diffie and M. E. Hellman. New directions in cryptography. IEEE Transactions on Information<br />

Theory, IT-22:644–654, November 1976.<br />

[ET75] S. Ev<strong>en</strong> and R.E. Tarjan. Network flow and testing graph connectivity. SIAM Journal on<br />

Computing, 4:507–518, 1975.<br />

[ET76] S. Ev<strong>en</strong> and R. E. Tarjan. A combinatorial problem which is complete in polynomial space. In<br />

Proc. 7th ACM Symp. Theory of Computing, pages 710–719, 1976.<br />

[FF56] L.R. Ford and D.R. Fulkerson. Maximum flow through a network. Canadian Journal of Mathematics,<br />

8:399–404, 1956.<br />

153


[FHN + 03] H<strong>en</strong>ning Fernau, Torb<strong>en</strong> Hagerup, Naomi Nishimura, Prabhakar Ragde, and Klaus Reinhardt.<br />

On the parameterized complexity of the g<strong>en</strong>eralized rush hour puzzle. In Proc. 15th Canad.<br />

Conf. Comput. Geom., pages 6–9, 2003.<br />

[GHR95] R. Gre<strong>en</strong>law, H.J. Hoover, and W.L. Ruzzo. Limits to Parallel Computation: P-Complet<strong>en</strong>ess<br />

Theory. Oxford University Press, 1995.<br />

[GJ79] M.R. Garey and D.S. Johnson. Computing and Intractability, A Guide to the Theory of NP-<br />

Complet<strong>en</strong>ess. W.H. Freeman and Company, New York, 1979.<br />

[GT02] M.T. Goodrich and R. Tamassia. Algorithm Design. Wiley, 2002.<br />

[Har92] D. Harel. Algorithmics, the Spirit of Computing. Addison Wesley, 1992.<br />

[Hea05] Robert A. Hearn. Amazons is pspace-complete, 2005.<br />

[HNR68] P.E. Hart, N.J Nilsson, and B. Raphael. A formal basis for the heuristic determination of<br />

minimum cost paths. IEEE Transactions on Systems Sci<strong>en</strong>ce and Cybernetics, 4(2):100–107,<br />

1968.<br />

[HS76] Juris Hartmanis and Janos Simon. On the structure of feasible computations. Ad<strong>van</strong>ces in<br />

Computers, 14:1–43, 1976.<br />

[IK94] S. Iwata and T. Kasai. The othello game on an n×n board is pspace-complete. Theoretical<br />

Computer Sci<strong>en</strong>ce, 123:329–340, 1994.<br />

[Imm88] N. Immerman. Nondeterministic space is closed under complem<strong>en</strong>tation. SIAM J. Comput.,<br />

17:935–938, 1988.<br />

[JS04] R. Johnsonbaugh and M. Schaefer. Algorithms. Pearson, 2004.<br />

[Kha80] L.G. Khacian. Polynomial algorithms in linear programming. Zh. vychisl. Mat. mat. Fiz,<br />

20(1):51–68, 1980.<br />

[Knu73] D.E. Knuth. The Art of Computer Programming, volume 3. Addison Wesley, 1973.<br />

[LFKN90] C. Lund, L. Fortnow, H. Karloff, and N. Nisan. Algebraic methods for interactive proof systems.<br />

In Proc. 31st Symposium on Foundations of Computer Sci<strong>en</strong>ce, pages 2–90, New York, 1990.<br />

IEEE.<br />

[LS80] D. Licht<strong>en</strong>stein and M. Sipser. Go is polynomial-space hard. Journal of the ACM, 27:393–401,<br />

1980.<br />

[Meh85] K. Mehlhorn. Graph Algorithms and NP-Complet<strong>en</strong>ess. EATCS Monographs on Theoretical<br />

Computer Sci<strong>en</strong>ce. Springer-Verlag, 1985.<br />

[MKM78] Vishv M. Malhotra, M. Pramodh Kumar, and S. N. Maheshwari. An o(—v—) algorithm for<br />

finding maximum flows in networks. Inf. Process. Lett., 7(6):277–278, 1978.<br />

[Par99] R. Parkinson. Cracking Codes, the Rosetta Stone, and Decipherm<strong>en</strong>t. University of California<br />

Press, 1999.<br />

[Pom96] C. Pommerance. A tale of two sieves. Notices of the American Mathematical Society,<br />

43(12):1473–1485, 1996.<br />

[Rei05] O. Reingold. Undirected ST-connectivity in LOGSPACE. In Proceedings 37th Annual ACM<br />

Symposium on Theory of Computing, pages 376–385, 2005.<br />

154


[RS83] N. Robertson and P.D. Seymour. Graph minors. i. excluding a forest. Journal of Combinatorial<br />

Theory Series B, 35(1):39–61, 1983.<br />

[RS04] N. Robertson and P.D. Seymour. Graph minors. xx. wagner’s conjecture. Journal of Combinatorial<br />

Theory Series B, 92(2):325–357, 2004.<br />

[RSA78] R.L. Rivest, A. Shamir, and L. Adleman. A method for obtaining digital signatures and publickey<br />

cryptosystems. Communications of the ACM, 21(2):120–126, 1978.<br />

[Sha92] A. Shamir. IP=PSPACE. Journal of the ACM, 4:869–877, October 1992.<br />

[Ski98] S. Ski<strong>en</strong>na. The Algorithm Design Manual. Springer Verlag, 1998.<br />

[Sto76] L. Stockmeyer. The polynomial-time hierarchy. Theoretical Computer Sci<strong>en</strong>ce, 3:1–22, 1976.<br />

[Str69] V. Strass<strong>en</strong>. Gaussian elimination is not optimal. Numerische Mathematik, 13:354–356, 1969.<br />

[Sze87] R. Szelepsényi. The method of forcing for nondeterministic automata. Bulletin of the EATCS,<br />

33:96–100, 1987.<br />

[Tur36] A. M. Turing. On computable numbers, with an application to the Entscheidungsproblem.<br />

Proceedings of the London Mathmatical Society, 42(2):230–265, 1936.<br />

[Wil86] H.S. Wilf. Algorithms and Complexity. Pr<strong>en</strong>tice-Hall International Editions, 1986.<br />

155


Index<br />

O, 24<br />

Ω, 24<br />

ω, 24<br />

∼, 25<br />

θ, 25<br />

o, 24<br />

3-KLEURBAARHEID, 120<br />

3SAT, 109<br />

Adleman, 80<br />

Akra, 29<br />

Alembert<br />

integraalk<strong>en</strong>merk <strong>van</strong> d’-, 149<br />

algoritme<br />

- <strong>van</strong> Kruskal, 150<br />

- <strong>van</strong> Prim, 151<br />

- <strong>van</strong> Strass<strong>en</strong>, 152<br />

beslissings-, 145<br />

Euclidische -, 69<br />

expon<strong>en</strong>tiële tijd begr<strong>en</strong>sde -, 102<br />

Ford-Fulkerson, 64<br />

Ford-Fulkerson -, 148<br />

gulzige -, 35, 148<br />

Khacian’s -, 149<br />

optimalisatie -, 35<br />

optimaliserings -, 150<br />

probabilistische -, 151<br />

simplex-, 152<br />

Uitgebreide Euclidische -, 69<br />

versleutelings-, 152<br />

analyse<br />

complexiteits-, 146<br />

argum<strong>en</strong>t<br />

adversary -, 145<br />

Aristoteles, 69<br />

articulatiepunt, 145<br />

axioma, 140<br />

barometer, 145<br />

Bazzi, 29<br />

BEGRENSDE BETEGELING, 115<br />

beslissingsalgoritme, 145<br />

beslissingsprobleem, 145<br />

156<br />

betegeling<br />

begr<strong>en</strong>sde -, 145<br />

betrekking<br />

eerstegraads recurr<strong>en</strong>te -, 28<br />

recurr<strong>en</strong>te -, 28, 152<br />

blowfish, 146<br />

BOEDELSCHEIDING, 119<br />

boedelscheiding, 146<br />

boom<br />

opspann<strong>en</strong>de -, 38, 150<br />

BOUNDED TILING, 103, 145<br />

bov<strong>en</strong>gr<strong>en</strong>s<br />

expon<strong>en</strong>tiële -, 63<br />

bov<strong>en</strong>gr<strong>en</strong>z<strong>en</strong>, 24<br />

branch & bound, 146<br />

Branch <strong>en</strong> Bound, 127<br />

breadth first search, 146<br />

Cantor, G., 13<br />

capaciteit, 62<br />

rest-, 63<br />

CHROMATIC NUMBER, 120<br />

circuit, 146<br />

Hamilton -, 148<br />

circuit value problem, 146<br />

CLIQUE, 103, 111<br />

clique, 146<br />

Cnidus<br />

Eudoxus <strong>van</strong> -, 69<br />

commitm<strong>en</strong>t<br />

bit -, 145<br />

complexiteit<br />

descriptieve -, 147<br />

geheug<strong>en</strong> -, 148<br />

uitgesmeerde -, 145<br />

uitgesmeerde - mbv bankmethode, 145<br />

complexiteitsklasses, 146<br />

complexiteitsmaat, 146<br />

complexity<br />

amortized -, 145<br />

compon<strong>en</strong>t<br />

dubbelverbond<strong>en</strong> -, 147<br />

verbond<strong>en</strong> -, 146


computing<br />

quantum -, 151<br />

connectivity, 146<br />

Cooley, 73<br />

Corm<strong>en</strong>, 29<br />

counting<br />

inductive -, 138<br />

cryptografie, 71, 78<br />

cryptosysteem<br />

block cypher, 79<br />

private key -, 78<br />

Public key -, 71, 80<br />

public key -, 78, 80<br />

cut<br />

min -, 146<br />

cykel, 147<br />

deelgraaf, 147<br />

deler<br />

grootste gem<strong>en</strong>e -, 69<br />

Depth First Search, 57<br />

DES, 147<br />

diagonalisatie, 147<br />

Diffie, 80<br />

Dijkstra<br />

algoritme <strong>van</strong> -, 37<br />

doorsnijding, 64<br />

capaciteit <strong>van</strong> -, 62<br />

minimale capaciteit, 62<br />

ELEMENTARY, 105, 148<br />

<strong>en</strong>tscheidungsproblem, 148<br />

Euclides<br />

algoritme <strong>van</strong> -, 69<br />

Uitgebreide -ische Algoritme, 147<br />

Euler, 112<br />

- toti<strong>en</strong>t functie, 80<br />

stelling <strong>van</strong> -, 80<br />

EULER CYCLE, 112<br />

EXACT COVER, 148<br />

EXACTE OVERDEKKING, 116<br />

EXP, 97<br />

FEEDBACK VERTEX SET, 148<br />

Feistel, H., 79<br />

Fermat<br />

stelling <strong>van</strong>, 81<br />

FFT, 73<br />

Ford, 64<br />

Fourier<br />

discrete - transformatie, 147<br />

Fast - Transform, 73<br />

inverse - transformatie, 76<br />

157<br />

Fulkerson, 64<br />

functie<br />

capaciteits-, 62<br />

capactietis-, 62<br />

stroom-, 62<br />

GENERALIZED GEOGRAPHY, 148<br />

getal<br />

Catalaans -, 146<br />

graaf, 64, 148<br />

HALT, 148<br />

HAMILTON CIRCUIT, 112<br />

HAMILTONIAN CIRCUIT, 149<br />

HANDELSREIZIGER, 114<br />

hashtabel, 149<br />

Helman, 80<br />

heuristiek, 149<br />

Hilbert, D., 13<br />

HITTING SET, 149<br />

INDEPENDENT SET, 103, 111, 149<br />

inproduct, 149<br />

instantie, 102<br />

kant<br />

capaciteit, 63<br />

klasse<br />

complexiteits-, 146<br />

kleurbaarheid, 149<br />

KLEURGETAL, 119<br />

kleurgetal, 149<br />

KNAPSACK, 146, 149<br />

knapsack, 36<br />

0-1, 51<br />

fractionele -, 37<br />

knoopoverdekking, 150<br />

knowledge<br />

zero - protocol, 150<br />

Kruskal<br />

algoritme <strong>van</strong> -, 150<br />

algoritme <strong>van</strong> -, 39<br />

Leiserson, 29<br />

lemma<br />

padding -, 151<br />

LOGSPACE, 150<br />

maat<br />

complexiteits, 146<br />

machine<br />

geklokte Turing –, 100<br />

nondeterministische Turing -, 97


nondeterministische Turing -, 104<br />

Turing -, 152<br />

unviversele Turing -, 98<br />

machinemodel<br />

random access -, 87<br />

redelijk -, 87<br />

Turing -, 89<br />

machtreeks, 150<br />

masterprobleem, 150<br />

masterreductie, 109, 150<br />

matching<br />

perfect -, 66, 150<br />

matrix, 45<br />

matrixverm<strong>en</strong>igvuldigingsexpon<strong>en</strong>t, 150<br />

Merkle<br />

key exchange <strong>van</strong> -, 80<br />

Merkle, P., 80<br />

methode<br />

pot<strong>en</strong>tiaal - voor uitgesmeerde complexiteit, 151<br />

minor, 150<br />

MRAM, 95, 150<br />

netwerk, 62, 64<br />

doorsnijding, 62<br />

Feistel -, 79<br />

gelaagd, 64, 66<br />

gelaagd -, 64<br />

NP, 150<br />

volledig probleem, 106<br />

number<br />

chromatic -, 146<br />

ODDMINSAT, 150<br />

ondergraaf, 150<br />

ondergr<strong>en</strong>s, 150<br />

oplosbaarheid<br />

Effici<strong>en</strong>t Oplosbaar Probleem, 23<br />

optimaliseringsalgoritme, 150<br />

optimaliseringsprobleem, 150<br />

overdekking, 151<br />

exacte -, 148<br />

knoop-, 150<br />

overdekkingsprobleem, 151<br />

P, 97, 151<br />

pad<br />

Euler -, 148<br />

one time -, 79<br />

stroomvergrot<strong>en</strong>d -, 64<br />

stroomvergrot<strong>en</strong>d -, 63–65, 152<br />

strooomvergrot<strong>en</strong>d -, 65<br />

padding, 100<br />

parallellisme<br />

158<br />

onbegr<strong>en</strong>sd -, 151<br />

PARTITION, 119, 146<br />

perebor, 102, 151<br />

PLANAIRE 3-KLEURBAARHEID, 121<br />

Pommerance, 80<br />

pot<strong>en</strong>tiaalmethode, 151<br />

PRAM, 94, 151<br />

priem<br />

relatief -, 69<br />

priemfactor, 151<br />

priemgetal, 151<br />

Prim<br />

algoritme <strong>van</strong> -, 151<br />

algoritme <strong>van</strong> -, 38<br />

primaliteit<br />

test, 151<br />

primaliteitstest, 151<br />

probleem<br />

begr<strong>en</strong>sde betegelings-, 103<br />

beslissings-, 145<br />

boedelscheiding, 103<br />

bron-, 105<br />

cricuit value -, 146<br />

doel-, 105<br />

exacte overdekkings -<br />

praktisch voorbeeld <strong>van</strong> e<strong>en</strong> -, 104<br />

exacte overdekkings-, 103<br />

handelsreiziger-, 149<br />

instantie <strong>van</strong> e<strong>en</strong> -, 102<br />

kleurbaarheids-, 103<br />

praktisch voorbeeld <strong>van</strong> -, 103<br />

knapsack-, 103<br />

knoopoverdekkings-, 103<br />

praktisch voorbeeld <strong>van</strong> e<strong>en</strong> -, 104<br />

master-, 150<br />

NP-volledig, 112<br />

NP-volledig -, 106<br />

onafhankelijke verzameling -, 103<br />

optimaliserings -, 150<br />

overdekkings-, 151<br />

traveling salesperson -, 103<br />

verdeel-, 116<br />

vervulbaarheids-, 103<br />

vervulbarheids -, 107<br />

vierkleur<strong>en</strong>-, 152<br />

volledige ondergraaf, 103<br />

processor, 87<br />

programma<br />

Turing machine -, 100<br />

programmer<strong>en</strong><br />

dynamisch -, 147<br />

PSPACE, 151


Pythagoras, 69<br />

QBF, 151<br />

quicksort, 151<br />

radix sort, 152<br />

RAM, 93<br />

EDIT -, 147<br />

multiplication, 95<br />

multiplication -, 150<br />

parallel, 94<br />

ram, 152<br />

redelijkheidsaanname, 87<br />

reductie, 105, 109, 152<br />

-schema, 109<br />

master-, 109, 150<br />

reductieschema, 109<br />

register, 87<br />

Rivest, 29, 80<br />

RSA, 80, 152<br />

SATISFIABILITY, 103, 107<br />

scheduling, 40<br />

- met deadlines, 41<br />

search<br />

breadth first -, 146<br />

exhaustive, 97<br />

exhaustive -, 102<br />

Shamir, 80<br />

sleutel, 78, 152<br />

uitwissel<strong>en</strong> <strong>van</strong> de -, 79<br />

sorter<strong>en</strong><br />

mergesort, 49<br />

ondergr<strong>en</strong>s voor -, 49<br />

quicksort, 47, 151<br />

radix sort, 152<br />

spil, 145, 152<br />

Standard<br />

Data Encryption -, 147<br />

stelling<br />

max-cut-min-flow, 64<br />

Strass<strong>en</strong>, 45<br />

algoritme <strong>van</strong> -, 152<br />

stroom, 62<br />

blokker<strong>en</strong>de -, 65<br />

maximale -, 62<br />

maximale-, 62<br />

stroomfunctie, 62<br />

thesis<br />

sequ<strong>en</strong>tial computation -, 87<br />

tijd<br />

Polynomiale -, 23<br />

159<br />

toestandsovergangsfunctie, 152<br />

tree<br />

mincost spanning -, 38<br />

TSP, 149<br />

Tukey, 73<br />

Turing<br />

- machine, 152<br />

Turingmachine<br />

halfoneindige band -, 91<br />

meerbands -, 91<br />

meerkops -, 91<br />

meertracks -, 91<br />

tweedim<strong>en</strong>sionale band -, 91<br />

variaties op het -model, 90<br />

versleuteling, 78<br />

asymmetrische -, 78<br />

symmetrische -, 78<br />

versleutelingsalgoritme, 152<br />

VERTEX COVER, 110, 149, 150<br />

vierkleur<strong>en</strong>probleem, 152<br />

volledig<br />

NP, 106<br />

waarheidswaard<strong>en</strong>, 152<br />

wissel<strong>en</strong><br />

geld -, gulzige algoritme, 36<br />

zelfreduceerbaarheid, 152<br />

zoekboom, 152<br />

zoekruimte, 152

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!