Opt regine cu Java

Următorul cod funcționează excelent, dar durează prea mult timp. placeQueens necesită și el mult timp. Programul durează 5-10 secunde.

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

Comentarii

  • Posibil, puteți utiliza o metodă de căutare cu retrogradare. Doar iterați plasarea reginelor una câte una, de fiecare dată alegând o primă poziție liberă (neocupată și ne atacată). Dacă nu există o poziție liberă pentru vreo regină n , retrageți-vă și mutați regina nr. ( n -1) de la locul curent la următoarea poziție liberă. Dacă ‘ nu are nicio poziție liberă, eliminați ( n -1) și reveniți înapoi. Dacă v-ați întors la tablă goală, nu mai există aranjamente regine posibile. Dacă ați mutat cu succes o regină ( n -1) în pasul ‘ înapoi ‘, continuați cu plasarea n -alea. Amplasarea aleatorie este prea ineficientă.
  • Unde funcția ‘ este main()?
  • @CiaPan mulțumesc, dar cred că există o soluție mai bună.
  • @TobySpeight invocă pur și simplu clasa în main() !!
  • ‘ nu poți invoca o clasă – poți construi o instanță a uneia sau invoca metodele statice ale acesteia. Se presupune că startSimulation() este funcția principală? Dacă da, l-ați putea numi main().

Răspuns

La fel ca bogosort nu va fi niciodată un algoritm rapid de sortare. Soluția dvs. „aruncați tabloul și plasați la întâmplare N regine noi” nu va fi niciodată mai rapidă decât acele 5-10 secunde.

Cu toate acestea, m-a bucurat să văd că de fapt găsește o soluție oarecum consecventă. Și întrebarea în sine este bine compusă, așa că cred că merită un răspuns.

Așa cum a sugerat deja CiaPan într-un comentariu, o modalitate mult mai bună de a rezolva problema n-reginelor este retracerea. Programul meu rapid de testare cu această abordare rezolvă 8-regine în 1 milisecundă (sau mai puțin). (Și cele 20 de regine în 50 ms).

Cu toate acestea, abordarea „resetează și plasează aleatoriu n regine noi” este interesant de văzut, așa că să adăugăm o îmbunătățire majoră pentru a accelera găsirea unui soluție.

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

Această mică schimbare de aici a redus timpul până la soluție sub 100 ms în mod constant. De ce? Deoarece acest lucru reduce spațiul de căutare de la O (n³) la O (n²). Motivul pentru care funcționează este că în toate soluțiile există exact 1 regină pe fiecare rând. Deci, generez una aleatorie pentru fiecare rând, în loc de pe întreaga placă.

Comentarii

  • Vă mulțumim pentru răspunsul grozav, dar se pare că ‘ s am terminat deja unul rapid, dar totuși am probleme cu regina aleatorie setată .
  • Există un alt punct demn de luat în considerare: @IbrahimAli nu a spus ‘ care a spus care este scopul său, găsind orice aranjament valid sau toate aranjamentele valide din 8 regine. Căutarea sistematică închisă într-o buclă va face acest lucru din urmă (revenire n toate soluțiile posibile și fiecare exact o dată), în timp ce generarea aleatorie nu poate (poate repeta răspunsurile și nu știm niciodată dacă a găsit toate posibilitățile; cu o calitate slabă a RNG, poate fi chiar incapabil să găsească).
  • @CiaPan I ‘ m gândesc pentru n poziția pentru n boolean pur și simplu creez un tablou boolean și îl folosesc ‘ s indexul depinde de random regine, fiecare regină generată am setat indexul ilegal la fals în matricea booleană, care va fi scurtă.
  • @Imus Nu aveți ‘ nu aveți nevoie de do – while buclă, deoarece fiecare placeQueens(i) invocată de bucla for (int i = 0; i < 8; i++) alocă o poziție într-un rând separat, prin urmare, coliziunile sunt imposibile, iar testarea pentru ele este o pierdere de timp.
  • Aha adevărat CiaPan. Bine reperat. Am făcut doar modificarea minimă pentru a genera una pe fiecare rând din codul original. De aceea ‘ este motivul pentru care tocmai am trecut în acel i la metodă. De asemenea, am observat verificarea acum redundantă, dar asta vă câștigă doar mai puțin de o milisecundă în găsirea soluției. Deci, nu poți ‘ chiar să faci diferența oricum.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *