Acht koninginnen met Java

De volgende code werkt prima, maar kost te veel tijd. placeQueens kost ook veel tijd. Het programma duurt 5-10 seconden.

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

Reacties

  • Eventueel kun je een zoekmethode gebruiken met backtracking. Herhaal het plaatsen van vrouwen een voor een, waarbij u elke keer een eerste vrije (niet bezette en niet aangevallen) positie kiest. Als er geen vrije positie is voor een n -de dame, doe dan een stap achteruit en verplaats de dame nr. ( n -1) van de huidige plaats naar de volgende vrije positie. Als er ‘ s geen vrije positie is, verwijder ( n -1) en stap weer terug. Als je terug bent gegaan naar een leeg bord, zijn er geen koninginarrangementen meer mogelijk. Als je met succes een dame ( n -1) hebt verplaatst in de stap ‘ terug ‘, ga dan verder met plaatsen de n -de. Willekeurige plaatsing is gewoon te ondoelmatig.
  • Waar ‘ is de main() -functie?
  • @CiaPan bedankt, maar ik denk dat er een betere oplossing is.
  • @TobySpeight roep gewoon de klas aan in de main() !!
  • Jij kan ‘ geen klasse aanroepen – je kunt er een instantie van construeren, of de statische methoden ervan aanroepen. Is startSimulation() de hoofdfunctie? Als dat zo is, zou je het in plaats daarvan main() kunnen noemen.

Answer

Net zoals zal bogosort nooit een snel sorteeralgoritme zijn. Je “gooi het bord weg en plaats willekeurig N nieuwe vrouwen” -oplossing zal nooit echt sneller zijn dan die 5 tot 10 seconden.

Desalniettemin maakte het me blij om te zien dat het eigenlijk een enigszins consequente oplossing vindt. En de vraag zelf is ook prima samengesteld, dus ik denk dat het een antwoord verdient.

Zoals CiaPan al in een opmerking suggereerde, is backtracking een veel betere manier om het n-queens-probleem op te lossen. Mijn snelle testprogramma met deze aanpak lost de 8-koninginnen op in 1 milliseconde (of minder). (En de 20-vrouwen in 50 ms).

De “reset en willekeurig n nieuwe vrouwen plaatsen” -benadering is echter interessant om te zien, dus laten we een belangrijke verbetering toevoegen om het vinden van een oplossing.

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

Deze kleine verandering hier zorgde ervoor dat de tijd tot de oplossing steeds lager was dan 100 ms. Waarom? Omdat dit de zoekruimte reduceert van O (n³) naar O (n²). De reden dat dit werkt, is dat er in alle oplossingen precies 1 dame op elke rij staat. Dus ik genereer een willekeurig voor elke rij, in plaats van op het hele bord.

Opmerkingen

  • Bedankt voor het goede antwoord, maar het lijkt erop dat ik ‘ de snelle al klaar ben maar nog steeds een probleem heb met de set random queen .
  • Er is nog een punt dat het overwegen waard is: @IbrahimAli heeft niet ‘ niet gezegd wat zijn doel eigenlijk is, door een geldige overeenkomst te vinden of alle geldige arrangementen van 8 Queens. Systematisch zoeken ingesloten in een lus zal het laatste doen (retur n alle mogelijke oplossingen, en elk precies één keer), terwijl willekeurig genereren dat niet kan (kan antwoorden herhalen en we weten nooit of het alle mogelijkheden heeft gevonden; met een slechte RNG-kwaliteit kan het zelfs niet zijn om er enkele te vinden).
  • @CiaPan Ik ‘ m denk aan n positie voor n boolean ik maak gewoon een booleaanse array en gebruik deze ‘ s index door afhangen van willekeurig queens, voor elke gegenereerde koninginnen heb ik de illegale index op false gezet in de booleaanse array die veel tijd zal kosten.
  • @Imus Je hebt ‘ de do – while -lus, aangezien elke placeQueens(i) die wordt aangeroepen door de for (int i = 0; i < 8; i++) -lus een positie in een aparte rij toewijst, vandaar dat botsingen onmogelijk zijn en het testen ervan tijdverspilling is.
  • Aha echte CiaPan. Goed gezien. Ik heb alleen de minimale wijziging aangebracht om er een te genereren op elke rij in de originele code. Dat ‘ is waarom ik zojuist die i aan de methode heb doorgegeven. Ik heb ook de nu overtollige controle opgemerkt, maar dat levert je slechts minder dan een milliseconde op bij het vinden van de oplossing. Dus je kunt ‘ het verschil toch niet echt zien.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *