150 likes | 364 Views
Backtracking. Suchen in Bäumen. Baumbegriffe. Der Suchraum ist die Menge aller für ein Problem bestehenden Lösungskandidaten . Der Suchbaum erzeugt den Suchraum und ermöglicht eine Ordnung. Wurzel. Vater. Kante. (innerer) Knoten. Blatt. Sohn. Suchraum für Mini-Sudoku.
E N D
Backtracking Suchen in Bäumen
Baumbegriffe • Der Suchraum ist die Menge aller für ein Problem bestehenden Lösungskandidaten. • Der Suchbaum erzeugt den Suchraum und ermöglicht eine Ordnung. Wurzel Vater Kante (innerer) Knoten Blatt Sohn
Suchraum für Mini-Sudoku Hier: 4^3 = 64 Möglichkeiten Anzahl möglicher Sudokus? • Mini (4er): • Komplett (9er):
Triple Zeichnen Sie einen Suchbaum, der alle Möglichkeiten generiert, wie aus der Zahlenmenge M = {1, 2, 3, 4, 5, 6} Tripel (i, j, k) zusammengesetzt werden können, so dass jede Zahl um mindestens 2 grösser als ihr Vorgänger ist Beschreiben Sie zu beiden Bäumen einen Algorithmus (als Struktigramm), der die Kindknoten eines inneren Knotens generiert
Permutationen • a) Schreiben Sie ein Programm, das Ihnen alle vierstelligen Zahlen ausgibt, die mit den Ziffern 1,2,3 gebildet werden können. • b) Wie kann das Programm erweitert werden, dass es ohne grosse Änderung für n-stellige Zahlen (mit den gleichen Ziffern 1,2,3) funktioniert?
Lösung a) int[] zahl = newint[4]; inti, j, k, l; for (i=1; i<=3; i++) { zahl[0]= i;for(j=1; j<=3; j++) { zahl[1] = j;for(k=1; k<=3; k++) { zahl[2] = k;for(l=1; l<=3; l++) { zahl[3] = l; println(join(nf(zahl, 0), ",␣")); // Ausgabe des Arrays } } } }
Lösung b) int[] zahl = newint[4]; // global definiert voidsetup() { generiereZiffernfolge(0); } voidgeneriereZiffernfolge(intmomTiefe) { inti;for(i=1; i<=3; i++) { // Ziffern von 1 bis 3 zahl[momTiefe] = i;if(momTiefe==3) { // sind bei zahl[3], also der vierten Stelle angelangtprintln(join(nf(zahl, 0), ",␣")); // Ausgabe des Arrays } else { generiereZiffernfolge(momTiefe+1); //rekursiver Aufruf } } }
Lösung b) int[] zahl = newint[n]; // global definiert voidsetup() { generiereZiffernfolge(0); } voidgeneriereZiffernfolge(intmomTiefe) { inti;for(i=1; i<=3; i++) { // Ziffern von 1 bis 3 zahl[momTiefe] = i;if(momTiefe==n-1) { // sind bei zahl[3], also der vierten Stelle angelangtprintln(join(nf(zahl, 0), ",␣")); // Ausgabe des Arrays } else { generiereZiffernfolge(momTiefe+1); //rekursiver Aufruf } } }
Suchbäume und Rekursion Die rekursive Programmierung eignet sich gut, um eine Baumstruktur des Suchraums aufzubauen, da sie erlaubt, nur die Anweisungen für die Generierung der Kindknotenauf einer Tiefe anzugeben. Oft übergibt man dabei eine Variable (hier momTiefe), mit deren Hilfe man die Rekursion irgendwann abbricht Es ist jedoch durchaus möglich, den Suchbaum auch iterativ (statt rekursiv) aufzubauen.
Backtracking • Häufig kann ein Baum nicht direkt so konstruiert werden, dass nur Lösungen entstehen. Wir generieren dann einen grösserenBaum aller in Frage kommenden Möglichkeiten und testen diese, ob sie auch wirklich Lösungen sind. • Bemerken wir beim Generieren einer Teilmöglichkeiten, dass diese unter keinen Umständen zu einer vollen Lösung ausgebaut werden kann, verfolgen wir den entsprechenden Ast im Baum auch nicht mehr weiter.
Damenproblem Struktogramm für diesen Algorithmus (rekursiv?) Wie viele Möglichkeiten gibt es, 8 Damen auf einem Schachbrett so aufzustellen, dass keine Dame eine andere bedroht? Wie viele Möglichkeiten hätten wir uns mit Backtracking sparen können? Etwas überschaubarer: 4 Damen auf 4x4 Brett
Sudoku mit Backtracking Zeichnen Sie ein (grobes) Struktogramm für einen Algorithmus, der mittels Backtracking beliebige Sudokus lösen kann. Lösungsansatz: • Trage alle Singletons ein. • Breche ab, wenn es für eine Zelle keine Kandidaten gibt. • Trage in eine leere Zelle einen Probewert ein. • Rufe das Programm rekursiv auf.