HSG |
|
Tiefensuche versucht durch stetiges Erweitern eines Weges zum Ziel zu gelangen. Im Misserfolgsfall werden durch Backtracking andere Verzweigungen gewählt.
pfeil(a,b). pfeil(a,c). pfeil(a,d). pfeil(b,c). pfeil(c,d). pfeil(c,e). pfeil(d,e). pfeil(c,a). weg(X,Y):-pfeil(X,_),pfeil(_,Y),tiefensuche(X,Y,Loesung). tiefensuche(Start,Ziel,Loesung):-tiefensuche(Start,[Start],Ziel,Loesung). tiefensuche(Ziel,Pfad,Ziel,Loesung):-Loesung = Pfad,!. tiefensuche(KnotenA,Pfad,Ziel,Loesung):-pfeil(KnotenA,KnotenN), not(member(KnotenN,Pfad)), tiefensuche(KnotenN,[KnotenN|Pfad],Ziel,Loesung).
In "tiefensuche(Ziel,Pfad,Ziel,Loesung):-Loesung = Pfad,!." wird ein Cut verwendet und es kommt die 'Akkumulatortechnik' zur Anwendung.
Tiefensuche kann im Einzelfall sehr ungünstig verlaufen.
pfeil(a,b). pfeil(a,c). pfeil(a,d). pfeil(b,c). pfeil(c,d). pfeil(c,e). pfeil(d,e). pfeil(c,a). weg(X,Y):-pfeil(X,_),pfeil(_,Y),weg1(X,Y,[],[]). weg1(Start,Ziel,Anwaerter,Besucht):-Start=Ziel, append(Besucht,[Ziel],Route),write(Route). weg1(Start,Ziel,Anwaerter,Besucht):-append(Besucht,[Start],BesuchtNeu), findall(N,pfeil(Start,N),Nachfolger), append(Nachfolger,Anwaerter,AnwaerterNeu), subtract(AnwaerterNeu,BesuchtNeu,[K|R]), weg1(K,Ziel,[K|R],BesuchtNeu).
'Schachteldiagramm' zu weg1(a,e,[ ],[ ]).
append (append(L1,L2,L3) fügt die Listen L1 und L2 zu L3 zusammen),
findall ( findall(X,p(X),L) sammelt in der Liste L alle X, die p(X) wahr machen) ,
subtract ( subtract(A,B,D) ermittelt die Differenzmenge D = A\B )
Der Abbruch bei leerer Anwärterliste geschieht in subtract(AnwaerterNeu,BesuchtNeu,[K|R]) , weil [ ] = [K|R] fehlschlägt.
Algorithmus 2 findet höchstens eine Lösung und ist aufwändiger, Algorithmus 1 findet alle Lösungen und ist kürzer.
In der Aufgabe 21 auf Seite 26 von G.Röhner, Informatik mit Prolog soll ein Weg von a nach g gesucht werden. Herr Röhner schlägt vor, das Labyrinth durch die vorhandenen Türen zu beschreiben. Da man eine Tür in beiden Richtungen beschreiten kann, lässt sich mit pfeil(X,Y):-tuer(X,Y). und pfeil(Y,X):-tuer(X,Y). eine Anpassung an obige Notation vornehmen. |
tuer(a,b). tuer(b,e). tuer(b,c). tuer(d,e). tuer(c,d). tuer(e,f). tuer(g,e). pfeil(X,Y):-tuer(X,Y). pfeil(X,Y):-tuer(Y,X). tiefensuche(Start,Ziel,Loesung):-pfeil(Start,_),pfeil(_,Ziel), tiefensuche(Start,[Start],Ziel,Loesung). tiefensuche(Ziel,Pfad,Ziel,Loesung):-Loesung = Pfad,!. tiefensuche(KnotenA,Pfad,Ziel,Loesung):-pfeil(KnotenA,KnotenN), not(member(KnotenN,Pfad)), append(Pfad,[KnotenN],PfadNeu), tiefensuche(KnotenN,PfadNeu,Ziel,Loesung).
Obiges Programm verwendet eine leicht modifizierte Tiefensuche: Neue Knoten werden mit append hinten an den Pfad angehängt. So wird der Pfad am Schluss in der richtigen Orientierung ausgegeben.
?- tiefensuche(a,g,L). L = [a, b, e, g] ; L = [a, b, c, d, e, g] ;