Kahdeksan Java-kuningatarta

Seuraava koodi toimii hyvin, mutta vie liian paljon aikaa. placeQueens vaatii myös paljon aikaa. Ohjelma kestää 5–10 sekuntia.

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

Kommentit

  • Ehkä voit käyttää hakutapaa taaksepäin. Vain toista kuningattarien asettaminen yksitellen, joka kerta, kun valitset ensimmäisen vapaan (ei miehitetyn eikä hyökätyn) sijainnin. Jos jollekin n – kuningattarelle ei ole vapaata paikkaa, astu taaksepäin ja siirrä kuningatar nro. ( n -1) nykyisestä paikasta seuraavaan vapaaseen sijaintiin. Jos ’ ei ole vapaata sijaintia, poista ( n -1) ja astu takaisin. Jos astut takaisin tyhjälle laudalle, ei ole enää mahdollisia kuningatarjärjestelyjä. Jos siirrit kuningattaren ( n -1) onnistuneesti ’ takaisin ’ -vaiheessa, jatka sijoittamista n – toinen. Satunnainen sijoittaminen on aivan liian tehokasta.
  • Missä ’ on main() -toiminto?
  • @CiaPan kiitos, mutta mielestäni on olemassa parempi ratkaisu.
  • @TobySpeight yksinkertaisesti kutsuu luokan main() !!
  • Sinulle ’ ei voi kutsua luokkaa – voit luoda niistä yhden tai kutsua sen staattisia menetelmiä. Onko startSimulation() oltava päätoiminto? Jos näin on, voit kutsua sitä main().

Vastaa

Aivan kuten bogosort ei koskaan tule olemaan nopea lajittelualgoritmi. ”Heitä lauta pois ja sijoita satunnaisesti N uutta kuningatarta” -ratkaisusi ei todellakaan ole nopeampi kuin 5-10 sekuntia.

Siitä huolimatta se sai minut iloiseksi huomatessani, että se todella löytää ratkaisun jonkin verran johdonmukaisesti. Ja itse kysymys koostuu myös hyvin, joten mielestäni se ansaitsee vastauksen.

Kuten CiaPan ehdotti jo kommentissa, paljon parempi tapa ratkaista n-kuningattaren ongelma on takaisku. Pika testiohjelmani tällä lähestymistavalla ratkaisee 8 kuningattaret 1 millisekunnissa (tai vähemmän). (Ja 20-kuningattaret 50 sekunnissa).

Kuitenkin ”nollaa ja sijoita satunnaisesti uudet kuningattaret” -lähestymistapa on mielenkiintoinen nähdä, joten lisätään yksi merkittävä parannus nopeuttaaksemme ratkaisu.

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

Tämä pieni muutos sai ratkaisun ajan tasaisesti alle 100 ms: iin. Miksi? Koska tämä vähentää hakutilaa O: sta (n³) O: ksi (n²). Syynä tähän on se, että kaikissa ratkaisuissa on täsmälleen yksi kuningatar kullakin rivillä. Joten tuotan yhden satunnaisesti kullekin riville koko taulun sijaan.

Kommentit

  • Kiitos upeasta vastauksesta, mutta näyttää siltä, että olen jo valmistunut nopeasti, mutta minulla on edelleen ongelmia asetetun satunnaisen kuningattaren kanssa .
  • On vielä yksi huomioitava arvoinen seikka: @IbrahimAli ei sanonut ’ ei sanonut, mikä hänen tarkoituksensa on, löytää mikä tahansa pätevä järjestely tai kaikki voimassa olevat 8 kuningattaren järjestelyt. Silmukkaan suljettu järjestelmällinen haku tekee jälkimmäisen (palaa n kaikki mahdolliset ratkaisut, ja kukin täsmälleen kerran), vaikka satunnainen generointi ei voi (voi hyvinkin toistaa vastauksia, emmekä koskaan tiedä löytyykö kaikki mahdollisuudet; huonolla RNG-laadulla se voi olla jopa mahdotonta löytää niitä.
  • @CiaPan I ’ ajattelee n sijainti n loogiselle logolle yksinkertaisesti luon loogisen taulukon ja käytän sitä ’ -indeksin mukaan riippuen satunnaisesta kuningattaret, jokainen luoma kuningatar, asetan laittoman indeksin vääräksi loogisessa taulukossa, joka kestää paljon aikaa.
  • @Imus Et tarvitse ’ et tarvitse do – while -silmukka, koska kukin placeQueens(i) -silmukka, johon for (int i = 0; i < 8; i++) -silmukka kutsuu, jakaa sijainnin erillisellä rivillä, törmäykset ovat siten mahdotonta, ja niiden testaaminen on ajanhukkaa.
  • Aha true CiaPan. Hyvin huomattu. Tein vain pienimmän muutoksen luoda yksi kullekin riville alkuperäisessä koodissa. Siksi ’ s miksi välitin juuri tämän i menetelmän. Huomasin myös nyt tarpeettoman tarkistuksen, mutta se saa vain alle millisekunnin ratkaisun löytämisessä. Joten et voi ’ t todellakaan kertoa eroa joka tapauksessa.

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *