Anvendelser III
description
Transcript of Anvendelser III
1
Anvendelser III
Grafer
2
• Grafer
Terminologi
Repræsentation
Traversering af grafer
Korteste vej
Topologisk sortering
• Problemkompleksitet og afgørlighed
Plan
3
Grafer
En graf er et nyttigt, abstrakt begreb.
Intuitiv definition: En graf er en mængde af objekter og forbindelser imellem disse.
Matematisk definition: En graf G = (V,E) består af en endelig mængde af knuder, V, og en endelig mængde af kanter, E, hvor hver kant forbinder to af knuderne (E VxV).
A
B C G
F
D E
H I
V = A, B, C, D, E, F, G, H, I
E = (A,B), (A,C), (A,F), (A,G), (D,E), (D,F), (E,F), (E,G), (H,I)
4
Anvendelsesområder
Alt, hvad der involverer relationer imellem
objekter, kan modelleres ved hjælp af en graf
Trafiknetværk: Knuder: byer, vejkryds Kanter: veje
Organiske molekyler: Knuder: atomer Kanter: bindinger
Elektriske kredsløb: Knuder: komponenter Kanter: ledninger
5
Objektorienteret design (UML-diagrammering): Knuder: klasser/objekter Kanter: nedarvning, aggregering eller associering
Projektplanlægning: Knuder: delopgaver Kanter: præcedenser (delopgave A skal udføres før delopgave B)
Programsystemer: Knuder: metoder Kanter: metode A kan kalde metode B
Anvendelsesområder(fortsat)
6
Terminologi
En orienteret graf er en graf, hvor alle kanter er orienterede. En ikke-orienteret graf er en graf, hvor ingen kanter er orienterede.
H I
Hvis rækkefølgen af en kants endeknuder har betydning, kaldes kanten for orienteret.
Dette angives på den grafiske repræsentation ved at kanten forsynes med en pil. Endeknuderne kaldes da for henholdsvis begyndelsesknuden og slutknuden.
H I
En kants 2 knuder kaldes endeknuder for kanten.
7
Terminologi (fortsat)
En vej er en liste af knuder, hvor successive knuder er forbundet med en kant.
En vej kaldes simpel, hvis ingen knude gentages.
En cykel er en vej, der er simpel, bortset fra at den første og sidste knude er den samme.
A
B C G
F
D E
Cykler: FDEF, AFEGA og AFDEGA.
8
En graf G’ = (V’,E’) er en delgraf af G = (V,E), hvis V’ Vog E’
E.
En graf kaldes sammenhængende, hvis der for enhver knude findes en vej til enhver anden knude.
En graf, der ikke er sammenhængende, består af sammenhængende delgrafer, også kaldet komponenter.
A
B C G
F
D E
H I
2 komponenter
Terminologi (fortsat)
9
Et træ er en sammenhængende graf uden cykler.
En mængde af disjunkte træer kaldes en skov.
Et udspændende træ for en graf G er en delgraf af G, der indeholder alle grafens knuder, og som udgør et træ.
Graf G Udspændende træ for G
Terminologi (fortsat)
10
En graf, hvor enhver knude er forbundet med enhver anden knude, kaldes for komplet.
[ for en ikke-orienteret graf: |E| = |V|*(|V|-1)/2) ]
En tynd graf er en graf med relativt få kanter (i forhold til |V|)
En tæt graf er en graf med relativt mange kanter (i forhold til |V|)
En vægtet graf er en graf, hvor kanterne er forsynet med talværdier, kaldet vægte.[ vægtene repræsenterer normalt omkostninger ]
Terminologi (fortsat)
11
Basale grafproblemer
Veje: Er der en vej fra knude A til knude B?
Cykler:Indeholder grafen en cykel?
Sammenhæng (udspændende træ): Er der for hver knude en vej til enhver anden knude?
2-sammenhæng: Vil grafen blive usammenhængende, hvis en af knuderne (og de tilstødende kanter) fjernes?
Planaritet: Kan grafen tegnes, uden at to kanter krydser hinanden?
12
Basale grafproblemer(fortsat)
Korteste vej:Hvilken vej er den korteste mellem knude A og knude B?
Længste vej: Hvilken vej er den længste mellem knude A og knude B?
Minimalt udspændende træ: Hvad er den billigste måde at forbinde alle knuder?
Hamilton-cykel: Er der en cykel, som indeholder samtlige knuder?
Den rejsende sælgers problem: Hvilken Hamilton-cykel er den billigste?
13
Repræsentation af grafer
Grafer er abstrakte matematiske objekter.Algoritmer må arbejde med konkrete repræsentationer.
Mange mulige repræsentationer. Valget er bestemt af algoritmer og graftyper (tynde/tætte, vægtede/uvægtede, orienterede/ikke-orienterede).
I det følgende gennemgås 3 repræsentationer:
(1) kantmængde (2) nabomatrix (3) nabolister
14
(1) Kantmængde-repræsentation
class Edge
Vertex source, dest;
int cost;
class Graph Vector edges;
class Vertex String name;
15
(2) Nabomatrix-repræsentation
A B C D E F G H I
A 0 1 1 0 0 1 1 0 0
B 1 0 0 0 0 0 0 0 0
C 1 0 0 0 0 0 0 0 0
D 0 0 0 0 1 1 0 0 0
E 0 0 0 1 0 1 1 0 0
F 1 0 0 1 1 0 0 0 0
G 1 0 0 0 1 0 0 0 0
H 0 0 0 0 0 0 0 0 1
I 0 0 0 0 0 0 0 1 0
A
B C G
F
D E
H I
class Graph // uvægtet boolean adjMatrix[][];
class Graph // vægtet int adjMatrix[][];
16
(3) Naboliste-repræsentation
A
B C G
F
D E
H IA:
B:
C:
D:
E:
F:
G:
H:
I:
F C B G
A
A
F E
G F D
A E D
E A
I
H
17
Naboliste-repræsentation
class Edge
Vertex dest; // Second vertex of edge
int cost; // Edge cost
class Graph Vector vertices; // Table of vertices
class Vertex String name; // Vertex name List adj; // List of edges
18
Sammenligning af repræsentationer
Pladskrav:
Kantmængde: O(|E|)
Nabomatrix: O(|V|2)
Nabolister: O(|V| + |E|)
19
Værste tilfælde:
Er der en kant fra knude A til knude B? Kantmængde: O(|E|) Nabomatrix: O(1) Nabolister: O(|V|)
Er der en kant fra knude A? Kantmængde: O(|E|) Nabomatrix O(|V|) Nabolister: O(1)
Repræsentation har betydning for algoritmers effektivitet
20
Mål: at besøge enhver knude i grafen.
Dybde-først-traversering:
Rekursiv algoritme:
* Mærk alle knuder “ubesøgt”.
* Besøg startknuden.
* Ved besøg af en knude, v:Mærk knuden “besøgt” Besøg (rekursivt) alle ubesøgte
knuder, der er forbundet med v.
Traversering af grafer
Løser nogle simple grafproblemer: sammenhæng, cykler
Basis for løsning af nogle vanskelige grafproblemer:2-sammenhæng
21
class Vertex String name; List adj; boolean visited;
void visit() visited = true; ListItr p = new LinkedListItr(adj); for ( ; p.isInList(); p.advance) Vertex w = ((Edge) p.retrieve()).dest; if (!w.visited) w.visit();
Implementering af dybde-først-traversering
Kompleksitet: O(|E|)
22
Dybde-først-traversering af en komponent
A
B C G
F
D E
A
B C G
F
D E
A
B C G
D E
F
A
B C
D
G
E
F
A
B
D
C G
E
F
A
B C G
D E
F
A: F C B GB: AC: AD: F EE: G F DF: A E DG: E A
A
B C G
F
D E
23
Dybde-først-traversering af en sammenhængende graf repræsenteret ved nabolister kræver tid proportional med |E|
Dybde-først-traversering af en komponent udgør et dybde-først-træ
A
F C B
E
DG
1
2
3
4 5
6 7
24
void traverse(Vertex startVertex) Stack stack = new StackAr(); stack.push(startVertex); startVertex.visited = true; try while (!stack.isEmpty()) Vertex v = (Vertex) stack.topAndPop(); ListItr p = new LinkedListItr(v.adj); for ( ; p.isInList(); p.advance())
Vertex w = ((Edge) p.retrieve()).dest; if (!w.visited) stack.push(w); w.visited = true; catch (Underflow e)
Ikke-rekursiv dybde-først-traversering
Benyt en eksplicit stak af knuder.
25
Hvis stakken erstattes med en kø, foretages bredde-først-traversering.
Bredde-først-traversering
void traverse(Vertex startVertex) Queue queue = new QueueAr(); queue.enqueue(startVertex); startVertex.visited = true; try while (!queue.isEmpty()) Vertex v = (Vertex) queue.dequeue(); ListItr p = new LinkedListItr(v.adj); for ( ; p.isInList(); p.advance())
Vertex w = ((Edge) p.retrieve()).dest; if (!w.visited) queue.enqueue(w); w.visited = true; catch (Underflow e)
26
Bredde-først-traversering af en komponent
A: F C B GB: AC: AD: F EE: G F DF: A E DG: E A
A
B C G
F
D E
F C B G
A
B C G
F
D E
C B G E D
A
B C G
D E
F B G E D
A
B C G
D E
F G E D
A
B C G
D E
F E D
A
B C G
D E
F D
A
B C G
D E
F
27
A
F C B
E D
G
1
2 3 4 5
6 7
Bredde-først- traversering af en komponent udgør et bredde-først-træ
Bredde-først-traversering af en sammenhængende graf repræsenteret ved nabolister kræver tid proportional med |E|
28
Dybde-først versus bredde-først
Dybde-førststart
aktuel
Bredde-først
start
aktuel
29
Hvis køen erstattes med en prioritetskø, foretages bedste-først-traversering.
Bedste-først-traversering
void traverse(Vertex startVertex) PriorityQueue pq = new SpecialPriorityQueue(); pq.update(startVertex, priority); try while (!pq.isEmpty()) Vertex v = (Vertex) pq.retrieveMin(); v.visited = true; ListItr p = new LinkedListItr(v.adj); for ( ; p.isInList(); p.advance()) Vertex w = ((Edge) p.retrieve()).dest; if (!w.visited) pq.update(w, priority); catch (Underflow e)
30
SpecialPriorityQueue
pq.update(Object obj, int prio)
Hvis obj ikke findes i pq, så indsæt det med prioritet prio. Ellers, opdater dets prioritet til prio.
pq.retrieveMin()
Fjern fra pq det objekt, der har mindst prioritet. Returner dette objekt.
Denne abstrakte datatype findes ikke i pakken DataStructures.Men vi kan benytte klasserne PairHeap og PairNode til formålet.
31
Pairing Heap
class PairHeap
PairNode addItem(Comparable x);
Comparable deleteMin() throws Underflow;
void decreaseKey(PairNode p, Comparable newVal)
throws IllegalValue;
boolean isEmpty();
32
Ændringer i class Vertex
class Vertex implements Comparable String name; boolean visited; int priority = INFINITY; PairNode heapPosition; Vertex prev;
public int compares(Comparable rhs) Vertex v = (Vertex) rhs; return priority < v.priority ? -1 : priority == v.priority ? 0 : 1;
public boolean lessThan(Comparable rhs) return priority < ((Vertex) rhs).priority;
33
void traverse(Vertex startVertex) PairHeap pq = new PairHeap(); startVertex.priority = priority; startVertex.heapPosition = pq.addItem(startVertex); try while (!pq.isEmpty()) Vertex v = (Vertex) pq.deleteMin(); v.visited = true; ListItr p = new LinkedListItr(v.adj); for ( ; p.isInList(); p.advance()) Vertex w = ((Edge) p.retrieve()).dest; if (!w.visited && priority < w.priority) w.priority = priority; if (w.heapPosition == null) w.heapPosition = pq.addItem(w); else pq.decreaseKey(w.heapPosition, w); catch (Exception e)
34
Kompleksitet af bedste-først-søgning
Tidskompleksiteten for bedste-først-søgning i en graf er O((|V|+|E|)log|V|).
|V| kald af deletemin
|E| kald af enten addItem eller decreaseKey
Hvis pq er en hob, så er tiden for et kald af såvel deletemin, addItem som decreaseKey O(log|V|).
35
Korteste-vej-problemet
Find den korteste vej fra knude A til knude B.
Uvægtede korteste vej (minimer antallet af kanter fra A til B):Anvend bredde-først-traversering.Traverser grafen startende i A ved hjælp af en kø.
Vægtede korteste vej (bestem den billigste vej fra A til B):Anvend bedste-først-traversering: Dijkstras algoritme. Traverser grafen startende i A ved hjælp af en prioritetskø, idet prioriteten for hver ubesøgt knude er omkostningen af den hidtil billigste vej fra A til knuden.Virker dog kun i en graf med ikke-negative vægte.
36
Eksempel på bestemmelseaf korteste-vej-træ
A
B C G
F
D E
H I
J K
L M
1
2
1 2
2
1
1
6 32
1
1
2
1
5
1442
2
4 3
6
1
2
A
B C G
F
D E
H I
J K
L M
1
2
1 2
2
1
1
6 32
1
1
2
1
5
1442
2
4 3
6
2
2
3 5
A
B C G
F
D E
H I
J K
L M
1
2
1 2
2
1
1
6 32
1
1
2
1
5
1442
2
4 3
6
2
3 5
A
B C G
F
D E
H I
J K
L M
1
2
1 2
2
1
1
6 32
1
1
2
1
5
1442
2
4 3
6
4
3 4
37
A
B C G
F
D E
H I
J K
L M
1
2
1 2
2
1
1
6 32
1
1
2
1
5
1442
2
4 3
6
4
4
A
B C G
F
D E
H I
J K
L M
1
2
1 2
2
1
1
6 32
1
1
2
1
5
1442
2
4 3
6
5
4
7
A
B C G
F
D E
H I
J K
L M
1
2
1 2
2
1
1
6 32
1
1
2
1
5
1442
2
4 3
5
5
7
A
B C G
F
D E
H I
J K
L M
1
2
1 2
2
1
1
6 32
1
1
2
1
5
1442
2
4 3
5
7
38
A
B C G
F
D E
H I
J K
L M
1
2
1 2
2
1
1
6 3
2
1
1
2
1
5
1442
2
4 3
6
8A
B C G
F
D E
H I
J K
L M
1
2
1 2
2
1
1
6 3
2
1
1
2
1
5
1442
2
4 3
7
8
A
B C G
F
D E
H I
J K
L M
1
2
1 2
2
1
1
6 3
2
1
1
2
1
5
1442
2
4 3
88A
B C G
F
D E
H I
J K
L M
1
2
1 2
2
1
1
6 32
1
1
2
1
5
1442
2
4 3
8
A
B C G
F
D E
H I
J K
L M
1
2
1 2
2
1
1
6 32
1
1
2
1
5
1442
2
4 3
39
private boolean dijkstra(Vertex startVertex) clearData(); PairHeap pq = new PairHeap(); startVertex.priority = 0; startVertex.heapPosition = pq.addItem(startVertex); try while (!pq.isEmpty()) Vertex v = (Vertex) pq.deleteMin(); v.visited = true; ListItr p = new LinkedListItr(v.adj); for ( ; p.isInList(); p.advance()) Vertex w = ((Edge) p.retrieve()).dest;; int cvw = ((Edge) p.retrieve()).cost; if (cvw < 0) return false; if (!w.visited && v.priority + cvw < w.priority) w.priority = v.priority + cvw; w.prev = v; if (w.heapPosition == null) w.heapPosition = pq.addItem(w); else pq.decreaseKey(w.heapPosition, w); catch (Exception e) return true;
40
Minimalt udspændende træ
Hvis udtrykket v.priority + cvw overalt erstattes med cvw, vil det minimalt udspændende træ blive bestemt.
41
clearData
private void clearData() for (int i = 0; i < vertices.size(); i++) Vertex v = (Vertex) vertices.elementAt(i); v.visited = false; v.priority = INFINITY; v.prev = null;
42
Udskrivning af korteste vej
private void printPath(Vertex destVertex) if (destVertex.priority == INFINITY) System.out.println(destVertex.name + " is unreachable"); else destVertex.printPath(); System.out.println(" cost: " + destVertex.priority); System.out.println();
public void printPath() if (prev != null) prev.printPath(); System.out.print(" to "); System.out.print(name);
43
class Graph
public class Graph public Graph() vertices = new Vector(); vertexMap = new Hashtable(); // dictionary public Vertex addVertex(String vertexName) ... public void addEdge(String source, String dest, int cost) ... public boolean processRequest(BufferedReader in) ...
public static void main(String[] args) ... private static final int INFINITY = Integer.MAX_VALUE/3; private Vector vertices; private Hashtable vertexMap; private void printPath(Vertex destVertex) ... private void clearData() ... private boolean dijkstra(Vertex startVertex) ...
44
public static void main(String[] args) System.out.println("Enter graph file:");
BufferedReader in = new BufferedReader( new InputStreamReader(System.in));
BufferedReader graphFile;
try graphFile = new BufferedReader( new FileReader(in.readLine()));
catch(Exception e) System.err.println(e); return;
// ... fortsættes
main
45
Graph g = new Graph();try
String line;while ((line = graphFile.readLine()) != null)
StringTokenizer st = new StringTokenizer(line); try // read source, destination and cost
if (st.countTokens() != 3) throw new Exception();
String source = st.nextToken(); String dest = st.nextToken(); int cost = Integer.parseInt(st.nextToken()); g.addEdge(source, dest, cost); catch (Exception e)
System.err.println("Error: " + line);
catch (IOException e) System.err.println("Error: " + e );
while (g.processRequest(in));
main(forsat)
46
public void addEdge(String source, String dest, int cost) addVertex(source).adj.addElement(new Edge(addVertex(dest), cost));
addEdge
public Vertex addVertex(String vertexName) Vertex v; // lookup vertexname in the hashtable vertexMap if ((v = (Vertex) vertexMap.get(vertexName)) == null) vertices.addElement(v = new Vertex(vertexName)); vertexMap.put(vertexName, v); return v;
47
processRequestpublic boolean processRequest(BufferedReader in) String sourceName, destName; try
System.out.println("Enter start vertex:"); if ((sourceName = in.readLine()) == null) return false;
System.out.println("Enter destination vertex:"); if ((destName = in.readLine()) == null) return false;
catch (IOException e) System.out.println("Error: " + e); return false;
Vertex source, dest; if ((source = (Vertex) vertexMap.get(sourceName)) == null)
System.out.println("Start vertex not in graph"); return true;
if ((dest = (Vertex) vertexMap.get(destName)) == null) System.out.println("Destination vertex not in graph"); return true;
if (dijkstra(source)) printPath(dest);else System.out.println("Dijkstra fails - negative edge");
return true;
48
Kompleksitet
Dijkstras algoritme kan implementeres, så den har tidskompleksitet O((|E| + |V|)log(|V|).
Hvis alle vægte er ens, f.eks. 1, eksisterer en algoritme med tidskompleksitet O(|E|+|V|).
Hvis vægte må være negative, eksisterer en algoritme med tidskompleksitet O(|E||V|).
Hvis grafen ikke indeholder cykler, eksisterer en algoritme med tidskompleksitet O(|E|).
49
DAGs
En orienteret graf uden cykler kaldes for en DAG (Directed Acyclic Graph).
En DAG kan f.eks. benyttes til at modellere et aktivitetsnetværk, hvor pilene angiver, at en aktivitets færdiggørelse er en forudsætning for en andens påbegyndelse.
Eksempel: kursusforudsætninger.
50
Netværksplanlægning
aktivitet forgænger(e) varighed (uger)
A konstruer lagerstyringsmodel - 4
B implementer lagerstyringsprogram A 13
C konstruer prognosemodel - 4
D implementer prognoseprogram C 15
E indsaml data - 12
F design database A 4
G implementer database E, F 2
H oplær personale B, D 2
I afprøv system G, H 2
C D
H
B
E
A
F
G
Iaktivitetsnetværk
51
Dybde-først-traversering af en DAG
A
B C G
F
D E
H I
J K
L M
A J
F C B G K L
E
D
H
I
M
En skov for dybde-først-søgning har ingen opadgående kanter.
52
En DAG kan ordnes, således at ingen knude kommer før nogen anden knude, der peger på den. Denne operation kaldes topologisk sortering.
Topologisk sortering
A
B C G
F
D E
H I
J K
L M
Topologisk orden: Alle pile vender samme vej, fra venstre mod højre [ ikke unik ]
J K L M A G H I F E D B C
53
Omvendt topologisk orden kan opnås ved dybde-først-traversering.
Omvendt topologisk orden
A J
F C B G K L
E
D
H
I
M
D E F C B I H G A K M L J
54
void visit() visited = true; ListItr p = new LinkedListItr(v.adj); for ( ; p.isInList(); p.advance()) Vertex w = ((Edge) p.retrieve()).dest; if (!w.visited) w.visit(); stack.push(this);
Implementering af topologisk sortering
Tidskompleksitet: O(|E|)
55
Alternativ algoritme til topologisk sortering
(1) Lav en tom kø.
(2) Vælg en knude uden indgående kanter
(3) Indsæt knuden i køen. Fjern knuden og alle dens kanter fra grafen
(4) Gentag (2) og (3), indtil der ikke er flere knuder i grafen.
56
Implementering i Java
Queue tologicalOrder() for (int i = 0; i < vertices.size(); i++)
((Vertex) vertices.elementAt(i)).inDegree = 0; for (int i = 0; i < vertices.size(); i++)
Vertex v = (Vertex) vertices.elementAt(i); ListItr p = new LinkedListItr(v.adj); for ( ; p.isInList(); p.advance())
((Edge) p.retrieve()).dest.inDegree++;
Queue queue = new QueueAr(); for (int i = 0; i < vertices.size(); i++)
Vertex v = (Vertex) vertices.elementAt(i); if (v.inDegree == 0)
queue.enqueue(v);
// ... fortsættes
57
Queue result = new QueueAr(); try int iterations = 0; while (!queue.isEmpty() && ++iterations <= vertices.size()) Vertex v = (Vertex) queue.dequeue(); result.enqueue(v); ListItr p = new LinkedListItr(v.adj);
for ( ; p.isInList(); p.advance()) Vertex w = ((Edge) p.retrieve()).dest; if (--w.inDegree == 0) queue.enqueue(w);
catch (Underflow e) return iterations == vertices.size() ? result : null;
Implementering i Java(fortsat)
58
Problemkompleksitet og afgørlighed
59
Problemers kompleksitet
For en stor klasse af vigtige problemer kendes ingen løsningsalgoritmer, der kan garanteres at være hurtige.
En ineffektiv algoritme: køretiden vokser mindst eksponentielt [Ω(cn) ]
Et problem, der ikke kan løses med en effektiv algoritme, siges at være svært.
En effektiv algoritme: køretiden er opad begrænset af et polynomium [ O(nc) ]
Et problem, der kan løses med en effektiv algoritme, siges at være let.
60
Eksempler på svære problemer
• Den rejsende sælgers problem En sælger skal besøge N byer. Find en rejserute, der minimerer hans rejseomkostninger.
• Planlægning Et antal opgaver af varierende varighed skal udføres på to identiske maskiner inden en vis tidsfrist. Kan tidsfristen overholdes?
• Tilfredsstillelighed Er det muligt at tildele sandhedsværdier til variablerne i et logisk udtryk, som gør udtrykket sandt? (a b) (a b)
61
Flere eksempler på svære problemer
• Den længste vej Find den længste simple vej imellem to knuder i en graf.
• Opdeling Givet en mængde af heltal. Findes der en opdeling i to delmængder, således at summen af elementer i hver af de to delmængder er den samme?
• 3-farvning Kan knuderne i en graf farves med tre farver, således at hvert par af forbundne knuder har forskellig farve?
62
NP-komplette problemer
For intet af disse problemer kendes en algoritme, der løser problemet i polynomiel tid.
Alle eksperter er overbevist om, at en sådan algoritme ikke eksisterer. Det er dog endnu ikke bevist.
Problemerne tilhører den såkaldte klasse af NP-komplette problemer.
63
Et NP-komplet problem, er et problem der kan løses på en ikke-deterministisk maskine i polynomiel tid.
En ikke-deterministisk maskine er forsynet med den vidunderlige evne, at den i enhver valgsituation foretager det korrekte valg.
En sædvanlig, deterministisk maskine kan simulere korrekte valg i eksponentiel tid ved at afprøve enhver mulighed.
Hvis blot ét NP-komplet problem kan løses i polynomiel tid på en deterministisk maskine, så vil ethvert NP-komplet problem kunne løses i polynomiel tid.
NP-komplethed
64
Afgørlighed
Uafgørlige problemer er problemer, som ikke kan løses algoritmisk.
Eksempler:
• Bevis at en algoritme altid terminerer (Stopproblemet)
• Afgør om en sætning i prædikatlogikken er gyldig eller ej.
• Afgør om to syntaksbeskrivelser definerer det samme sprog.
65
(a)while (x != 1) x = x - 2;
Terminering?
while (x > 1) if (x%2 == 0) x = x/2; else x = 3*x + 1;
Collatz sekvenser: 12, 6, 3, 10, 5, 16, 8, 4, 2, 1
9,28,14,7,22,11,34,17,52,26,13,40,20,10,5,16,8,4,2,1
(b)
66
Programmets stopper, hvis og kun hvis Fermats sidste teorem er falsk.
For n ≥ 3 findes der ikke tre naturlige tal a, b, og c, så an + bn = cn.
P. de Fermat (1601-65)
(c) for (int x = 3; ; x++)
for (int a = 1; a <= x; a++)
for (int b = 1; b <= x; b++)
for (int c = 1; c <= x; c++)
for (int n = 3; n <= x; n++)
if (Math.pow(a,n) + Math.pow(b,n) == Math.pow(c,n))
System.exit(0);
Terminering?(fortsat)
67
Det er umuligt at konstruere en algoritme, der for enhver algoritme kan afgøre, om algoritmen terminerer.
Stopproblemet
Definer nu:
void p() while (terminates(p)) /* do nothing */;
Hvad returnerer da følgende kald: terminates(p)?
Bevis (indirekte):
Antag eksistensen af terminates(p), som for enhver metode p returnerer true, hvis p terminerer; ellers false.
68
Et spørgsmål
void p() while (terminates(p)) /* do nothing */;
void p() while (terminates(p)) /* do nothing */;
Som bekendt tillader Java ikke, at en metoder som parametre til metoder. Således er koden nedenfor ikke lovlig Java-kode:
Hvorledes kan den ønskede effekt alligevel opnås i Java?
69
Svar
class Method
void p()
while (terminates(this)) /* do nothing */;
og definer metoden terminates således:
static boolean terminates(Method m)
return ”kaldet m.p() vil terminere”;
Benyt en svøbeklasse (wrapper class) for metoden p:
70
• Læs kapitel 15, 16 og 17 i lærebogen (side 411-487)
• Løs følgende opgaver
7-1. Opgave 14.1
7-2. Opgave 14.2
7-3. Opgave 14.5
7-4. Opgave 14.7
Ugeseddel 723. oktober - 30. oktober