Åtta drottningar med Java

Följande kod fungerar bra men tar för mycket tid. placeQueens kräver också mycket tid. Programmet tar 5-10 sekunder.

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; } } 

Kommentarer

  • Eventuellt kan du använda en sökmetod med backtracking. Bara itera och placera drottningar en efter en, varje gång du väljer en första ledig (inte ockuperad och inte attackerad) position. Om det inte finns någon ledig position för någon n -te drottning, gå tillbaka och flytta drottningen nr. ( n -1) från nuvarande plats till nästa lediga position. Om det inte finns ’ tar du bort ( n -1) och går tillbaka igen. Om du gick tillbaka till tomt ombord finns det inga fler drottningsarrangemang. Om du framgångsrikt flyttat en drottning ( n -1) i steget ’ ’, fortsätt med att placera den n -te. Slumpmässig placering är alldeles för bristfällig.
  • Var ’ är main() -funktionen?
  • @CiaPan tack, men jag tror att det finns en bättre lösning.
  • @TobySpeight åberopar helt enkelt klassen till main() !!
  • Du kan ’ inte åberopa en klass – du kan konstruera en instans av en eller åberopa dess statiska metoder. Ska startSimulation() vara huvudfunktionen? Om så är fallet kan du kalla det main() istället.

Svara

Precis som bogosort kommer aldrig att vara en snabb sorteringsalgoritm. Din ”kasta bort styrelsen och slumpmässigt placera N nya drottningar” -lösningen kommer aldrig att bli snabbare än de 5 till 10 sekunderna.

Ändå gjorde det mig glad att se att den faktiskt hittar en lösning något konsekvent. Och själva frågan består också bra, så jag tycker att den förtjänar ett svar.

Som CiaPan redan föreslog i en kommentar är ett mycket bättre sätt att lösa n-drottningsproblemet med backtracking. Mitt snabba testprogram med detta tillvägagångssätt löser 8-drottningarna på 1 millisekund (eller mindre). (Och a 20-drottningarna på 50 ms).

Men ”Återställ och slumpmässigt placera n nya drottningar” är intressant att se, så låt oss lägga till en större förbättring för att påskynda lösning.

/** 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); } 

Den här lilla förändringen här fick tiden tills lösningen konsekvent blev under 100 ms. Varför? Eftersom detta minskar sökutrymmet från O (n³) till O (n²). Anledningen till att detta fungerar är att det i alla lösningar finns exakt 1 drottning på varje rad. Så jag genererar en slumpmässigt för varje rad istället för på hela tavlan.

Kommentarer

  • Tack för det fantastiska svaret, men det ’ s verkar som att jag redan har slutat snabbt en men ändå har problem med set random queen .
  • Det finns en annan punkt som är värt att överväga: @IbrahimAli gjorde inte ’ t säga vad hans mål egentligen är, att hitta något giltigt arrangemang eller alla giltiga arrangemang av 8 drottningar. Systematisk sökning i en slinga gör det senare (retur n alla möjliga lösningar, och var och en exakt en gång), medan slumpmässig generering inte kan (kan mycket väl upprepa svar och vi vet aldrig om det hittade alla möjligheter; med dålig RNG-kvalitet kan det till och med vara omöjligt att hitta några).
  • @CiaPan I ’ jag tänker på n position för n booleska helt enkelt skapar jag en boolean array och använder den ’ s index beroende på slumpmässigt drottningar, varje genererad drottning som jag ställer in olagligt index till falskt i den booleska matrisen som kommer att vara kort mycket tid.
  • @Imus Du behöver ’ t behöver do – while loop, eftersom varje placeQueens(i) anropas av for (int i = 0; i < 8; i++) -slingan tilldelar en position i en separat rad, Därför är kollisioner omöjliga och att testa för dem är slöseri med tid.
  • Aha sann CiaPan. Väl prickig. Jag gjorde bara den minsta ändringen för att generera en på varje rad i den ursprungliga koden. Det är ’ varför jag just skickade in det i till metoden. Jag märkte också den nu överflödiga kontrollen, men det ger dig bara mindre än ett millisekund när du hittar lösningen. Så du kan ’ verkligen inte se skillnaden.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *