Åtte dronninger med Java

Følgende kode fungerer bra, men tar for lang tid. placeQueens krever også mye 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

  • Eventuelt kan du bruke en søkemetode med backtracking. Bare gjenta å plassere dronninger en etter en, hver gang du velger en første ledig (ikke okkupert og ikke angrepet) posisjon. Hvis det ikke er noen ledig stilling for noen n -te dronning, gå tilbake og flytt dronningen nr. ( n -1) fra nåværende sted til neste ledige posisjon. Hvis det ‘ ingen ledig posisjon, fjerner du ( n -1) og går tilbake igjen. Hvis du gikk tilbake til tomt brett, er det ikke flere dronningsarrangementer. Hvis du vellykket flyttet en dronning ( n -1) i trinnet ‘ ‘, fortsett med å plassere den n -te. Tilfeldig plassering er bare for mangelfull.
  • Hvor ‘ er main() -funksjonen?
  • @CiaPan takk, men jeg tror det er en bedre løsning.
  • @TobySpeight påkaller ganske enkelt klassen i main() !!
  • Du kan ‘ ikke påkalle en klasse – du kan konstruere en forekomst av en, eller påkalle dens statiske metoder. Skal startSimulation() være hovedfunksjonen? I så fall kan du i stedet kalle det main().

Svar

Akkurat som bogosort vil aldri være en rask sorteringsalgoritme. Din «kaste brettet og tilfeldig plassere N nye dronninger» -løsningen vil aldri være raskere enn de 5 til 10 sekunder.

Likevel gjorde det meg glad å se at den faktisk finner en løsning noe konsekvent. Og selve spørsmålet er også sammensatt fint, så jeg synes det fortjener svar.

Som CiaPan allerede foreslo i en kommentar, er en langt bedre måte å løse n-dronningsproblemet med backtracking. Mitt hurtige testprogram med denne tilnærmingen løser 8-dronningene på 1 millisekund (eller mindre). (Og 20-dronningene på 50 ms).

Tilnærmingen «Tilbakestill og tilfeldig plassere nye dronninger» er imidlertid interessant å se, så la oss legge til en større forbedring for å øke hastigheten på å finne en 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); } 

Denne lille forandringen her fikk tiden til løsningen ned til under 100 ms konsekvent. Hvorfor? Fordi dette reduserer søkeområdet fra O (n³) til O (n²). Årsaken til at dette fungerer, er at det i alle løsningene er nøyaktig 1 dronning på hver rad. Så jeg genererer en tilfeldig for hver rad, i stedet for på hele tavlen.

Kommentarer

  • Takk for det flotte svaret, men det ser ut til at jeg ‘ ser ut til at jeg allerede er ferdig med en, men fortsatt har et problem med sett random queen .
  • Det er et annet poeng som er verdt å vurdere: @IbrahimAli sa ikke ‘ t si hva som faktisk er målet hans, og finne et hvilket som helst gyldig arrangement eller alle gyldige arrangementer av 8 dronninger. Systematisk søk i en sløyfe vil gjøre sistnevnte (retur n alle mulige løsninger, og hver nøyaktig en gang), mens tilfeldig generering ikke kan (kan godt gjenta svar, og vi vet aldri om den fant alle muligheter; med dårlig RNG-kvalitet kan det til og med være ute av stand å finne noen).
  • @CiaPan I ‘ jeg tenker på n posisjon for n boolsk rett og slett jeg oppretter en boolsk matrise og bruker den ‘ s indeks ved å avhenge av tilfeldig dronninger, hver genererte dronning setter jeg ulovlig indeks til falsk i den boolske matrisen som vil være kort, mye tid.
  • @Imus Du trenger ikke ‘ t do – while loop, da hver placeQueens(i) påkalt av for (int i = 0; i < 8; i++) loop tildeler en posisjon i en egen rad, derfor er kollisjoner umulige, og å teste for dem er bortkastet tid.
  • Aha ekte CiaPan. Godt observert. Jeg gjorde bare den minimale endringen for å generere en på hver rad i den opprinnelige koden. At ‘ er grunnen til at jeg nettopp passerte den i til metoden. Jeg la også merke til den nå overflødige kontrollen, men det gir deg bare mindre enn et millisekund for å finne løsningen. Så du kan ‘ ikke virkelig se forskjellen uansett.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *