Der folgende Code funktioniert hervorragend, nimmt aber zu viel Zeit in Anspruch. placeQueens
benötigt ebenfalls viel Zeit. Das Programm dauert 5-10 Sekunden.
public class EightQueen { public static void startSimulation(){ long startTime = System.currentTimeMillis(); char[] board; // Create an array // Repeat while queens are attacking do { // Generate a board board = getNewBoard(); // Place eight queens placeQueens(board); } while (isAttacking(board)); // Display solution print(board); long endTime = System.currentTimeMillis(); System.out.println(endTime - startTime); } /** placeQueens randomly places eight queens on the board*/ public static void placeQueens(char[] board) { int location; for (int i = 0; i < 8; i++) { do { location = placeQueens(); } while (isOccupied(board[location])); board[location] = "Q"; } } /** placeQueens randomly places one queen on the board */ public static int placeQueens() { return (int)(Math.random() * 64); } /** isAttacking returns true if two queens are attacking each other */ public static boolean isAttacking(char[] board) { return isSameRow(board) || isSameColumn(board) || isSameDiagonal(board); } /** isSameRow returns true if two queens are in the same row */ public static boolean isSameRow(char[] board) { int[] rows = new int[8]; for (int i = 0; i < board.length; i++) { if (isOccupied(board[i])) { rows[getRow(i)]++; } if (rows[getRow(i)] > 1) return true; } return false; } /** isSameColumn returns true if two queens are in the same column */ public static boolean isSameColumn(char[] board) { int[] columns = new int[8]; for (int i = 0; i < board.length; i++) { if (isOccupied(board[i])) { columns[getColumn(i)]++; } if (columns[getColumn(i)] > 1) return true; } return false; } /** isSameDiagonal returns true if two queens are on the same diagonal */ public static boolean isSameDiagonal(char[] board) { for (int i = 0; i < board.length; i++) { if (isOccupied(board[i])) { for (int j = 0; j < board.length; j++) { if (isOccupied(board[j]) && Math.abs(getColumn(j) - getColumn(i)) == Math.abs(getRow(j) - getRow(i)) && j != i) { return true; } } } } return false; } /** isOccupied returns true if the element in x is the char Q */ public static boolean isOccupied(char x) { return x == "Q"; } /** getNewBoard returns a char array filled with blank space */ public static char[] getNewBoard() { char[] board = new char[64]; for (int i = 0; i < board.length; i++) board[i] = " "; return board; } /** print displays the board */ public static void print(char[] board) { for (int i = 0; i < board.length; i++) { System.out.print( "|" + ((getRow(i + 1) == 0) ? board[i] + "|\n" : board[i])); } } /** getRow returns the row number that corresponds to the given index */ public static int getRow(int index) { return index % 8; } /** getColumn returns the column number that corresponds to the given index */ public static int getColumn(int index) { return index / 8; } }
Kommentare
- Möglicherweise können Sie eine Suchmethode verwenden mit Backtracking. Wiederholen Sie einfach die Platzierung der Königinnen nacheinander und wählen Sie jedes Mal eine erste freie Position (nicht besetzt und nicht angegriffen). Wenn es für eine n -te Königin keine freie Position gibt, treten Sie zurück und bewegen Sie die Königin Nr. ( n -1) vom aktuellen Ort zur nächsten freien Position. Wenn ‚ keine freie Position hat, entfernen Sie ( n -1) und treten Sie erneut zurück. Wenn Sie zurück zum leeren Brett getreten sind, gibt es keine möglichen Königinnenarrangements mehr. Wenn Sie eine Königin ( n -1) im Schritt ‚ zurück ‚ erfolgreich verschoben haben, fahren Sie mit dem Platzieren fort das n -te. Die zufällige Platzierung ist einfach zu unwirksam.
- Wo ‚ ist die Funktion
main()
? - @CiaPan danke, aber ich denke, es gibt eine bessere Lösung.
- @TobySpeight ruft einfach die Klasse in das
main()
!! - Sie auf ‚ kann eine Klasse nicht aufrufen – Sie können eine Instanz von einer erstellen oder ihre statischen Methoden aufrufen. Soll
startSimulation()
die Hauptfunktion sein? In diesem Fall können Sie es stattdessenmain()
nennen.
Antwort
Genau wie bogosort wird niemals ein schneller Sortieralgorithmus sein. Ihre Lösung „Werfen Sie das Brett weg und platzieren Sie zufällig N neue Königinnen“ wird nie wirklich schneller als diese 5 bis 10 Sekunden sein.
Trotzdem hat es mich glücklich gemacht zu sehen, dass es tatsächlich eine Lösung findet, die einigermaßen konsistent ist. Und die Frage selbst ist auch gut zusammengesetzt, daher denke ich, dass sie eine Antwort verdient.
Wie CiaPan bereits in einem Kommentar vorgeschlagen hat, ist das Zurückverfolgen ein weitaus besserer Weg, um das Problem der n-Königinnen zu lösen. Mein schnelles Testprogramm mit diesem Ansatz löst die 8 Königinnen in 1 Millisekunde (oder weniger). (Und die 20 Königinnen in 50 ms).
Der Ansatz „n neue Königinnen zurücksetzen und zufällig platzieren“ ist jedoch interessant zu sehen. Fügen wir also eine wesentliche Verbesserung hinzu, um das Auffinden von a zu beschleunigen Lösung.
/** placeQueens randomly places eight queens on the board*/ public static void placeQueens(char[] board) { int location; for (int i = 0; i < 8; i++) { do { location = placeQueens(i); } while (isOccupied(board[location])); board[location] = "Q"; } } /** placeQueens randomly places one queen on the board */ public static int placeQueens(int row) { return row * 8 + (int)(Math.random() * 8); }
Durch diese kleine Änderung wurde die Zeit bis zur Lösung konstant auf unter 100 ms gesenkt. Warum? Weil dies den Suchraum von O (n³) reduziert. Der Grund, warum dies funktioniert, ist, dass in allen Lösungen genau 1 Königin in jeder Reihe vorhanden ist. Daher generiere ich zufällig eine für jede Reihe anstatt auf der gesamten Tafel.
Kommentare
- Danke für die großartige Antwort, aber ‚ scheint, dass ich bereits schnell fertig bin, aber immer noch Probleme mit der eingestellten zufälligen Königin habe
- Es gibt noch einen weiteren erwägenswerten Punkt: @IbrahimAli hat ‚ nicht gesagt, was sein eigentliches Ziel ist, eine gültige Vereinbarung zu finden oder alle gültigen Anordnungen von 8 Königinnen. Die systematische Suche in einer Schleife führt letztere aus (Rückkehr) n alle möglichen Lösungen, und jede genau einmal), während zufällige Generierung nicht kann (kann durchaus Antworten wiederholen und wir wissen nie, ob es alle Möglichkeiten gefunden hat; Bei schlechter RNG-Qualität kann es sogar nicht möglich sein, einige zu finden.
- @CiaPan Ich ‚ denke nach
n
Position fürn
Boolescher Wert Ich erstelle einfach ein boolesches Array und verwende dessen ‚ Index abhängig vom Zufall Königinnen, jede generierte Königin, die ich im booleschen Array auf false gesetzt habe, was viel Zeit in Anspruch nimmt. - @Imus Sie benötigen ‚ nicht das
do – while
Schleife, da jedeplaceQueens(i)
, die von derfor (int i = 0; i < 8; i++)
-Schleife aufgerufen wird, eine Position in einer separaten Zeile zuweist. Daher sind Kollisionen unmöglich und das Testen auf sie ist Zeitverschwendung. - Aha true CiaPan. Gut erkannt. Ich habe nur die minimale Änderung vorgenommen, um eine in jeder Zeile im Originalcode zu generieren. Aus diesem Grund habe ich
i
an die Methode ‚ übergeben. Ich habe auch die jetzt redundante Prüfung bemerkt, aber das bringt Ihnen nur weniger als eine Millisekunde, wenn Sie die Lösung finden. Sie können also ‚ den Unterschied sowieso nicht wirklich erkennen.