N regine, domanda di intervista per problemi con le decisioni del consiglio X per Y


10

Mi è stata posta la seguente domanda in un'intervista oggi e ci ho pensato da allora. Non sono stato in grado di rispondere e non sono stato in grado di trovare una soluzione online.

Data una scacchiera con dimensioni X per le regine Y e N, determinare se è possibile disporre queste regine sulla scacchiera in modo che non possano attaccarsi a vicenda.

Una scheda 2 x 3 con 2 regine ha una soluzione in modo che l'algoritmo ritorni vero:

Q . .
. . Q

Sto cercando un approccio di programmazione a questo puzzle, non solo modi per risolverlo su carta, per esempio.


La migliore prima ricerca è certamente un'opzione, così come altre euristiche di ricerca
Jason,

2
nominato per una delle peggiori domande di intervista di sempre - a meno che il software su cui lavorano non si basi su soluzioni di backtracking, nel qual caso è del tutto rilevante
Steven A. Lowe,

1
Ad essere sinceri, l'intervistatore ha affermato che si trattava semplicemente di un credito extra. Il resto dell'intervista è stato abbastanza legittimo IMO. Ero solo curioso.
Intervistato

Forse è stato un test se avrebbe fatto una simulazione con backtracking o (pensa a trovare) O (1) soluzione usando i fatti dichiarati da Caleb nella sua risposta. La capacità di programmare cose semplici non è tutto ciò di cui si ha bisogno nel lavoro.
Sopel,

i compiti a casa sono esplicitamente fuori portata qui.
jwenting,

Risposte:


16

Questo non è (IMO) un problema molto interessante dal punto di vista della programmazione. Potresti trovare un algoritmo ricorsivo che prova ogni accordo, qualcosa del genere:

bool try_queens(Board board, int n)
{
    if (n == 0) {
        // no queens left to place, so we're done
        return true
    }
    // try each open position until we find one that works
    for each position on the board {
        if (is_empty(board, position) and not is_attacked(board, position)) {
            place_queen(board, position)
            if (try_queens(board, n-1)) {
                return true
            }
            remove_queen(board, position)
        }
    }
    // if we get this far, there's no available position
    return false
}

main()
{
    initialize board(X,Y)
    return try_queens(board, N)
}

Se pensi un po 'al problema, ti renderai conto che non c'è modo di adattare N regine su una scheda in cui X <N o Y <N perché ciò richiederebbe che almeno due regine finiscano nello stesso rango o file, e quindi si attaccerebbero l'un l'altro. Se leggi del problema n-queens, imparerai rapidamente che è sempre possibile posizionare N queens su una scheda NxN per N> 3. Ora sappiamo che la risposta è NO per (X <N o Y <N) e SÌ per (X> = N e Y> = N, N> 3). Tutto ciò che rimane sono i casi speciali:

  • N = 1 (SÌ)
  • N = 2 (SÌ per X> = 2 e Y> 2 o viceversa)
  • N = 3 (SÌ per X> = 3 e Y> 3 o viceversa)

Quindi ora la nostra bella funzione ricorsiva diventa una semplice funzione che confronta semplicemente N con X e Y e restituisce un risultato fisso. È fantastico dal punto di vista delle prestazioni, poiché puoi ottenere una risposta in tempo costante. Non è eccezionale dal punto di vista della programmazione perché ti rendi conto, a questo punto, che la domanda è davvero più su quanto puoi risolvere i puzzle piuttosto che sulla tua capacità di scrivere una funzione ricorsiva.

(E ragazzo oh ragazzo, spero davvero di non aver fatto qualche stupido errore nella mia risposta da smarty-pants. ;-)


That's great from a performance point of view, since you can get an answer in constant time. It's not so great from a programming point of view because you realize, at this point, that the question is really more about how well you can solve puzzles than it is about your ability to write a recursive function.In realtà penso che l'intervistatore stesse aspettando quella soluzione O (1) perché alla fine è migliore e non ovvia per molte persone. Il problema di nxn queen è in tutti i corsi di programmazione come un esercizio per la ricorsione - molte persone non penseranno più a fondo quando vedranno di nuovo quel problema.
Sopel,

4

Se l'intervistatore ti ha chiesto di scrivere il codice per il problema, penso che non sia giusto. L'algoritmo richiede lavoro. Tuttavia, se l'idea fosse quella di mostrare all'intervistatore le classi, i metodi o alcuni concetti che avresti bisogno di usare o qualcosa di simile, allora potrebbe essere una domanda giusta.

Il problema è un classico problema di informatica ed è discusso in molti di questi libri. Una spiegazione eccellente, con animazione e 12 diverse soluzioni insieme ad un po 'di codice può essere trovata qui:

http://en.wikipedia.org/wiki/Eight_queens_puzzle

Anche il codice può essere trovato qui: http://www.codeproject.com/KB/java/EightQueen.aspx

Non sentirti male, come ho detto, non è facile.


0

Questo è davvero più un commento, ma non si adatta lì ...

Una scacchiera ha 8x8 quadrati, non più né meno (queste domande mi infastidiscono sempre con quell'approccio di una scacchiera personalizzata).

Ma comunque, se hai una scacchiera x * y e n regine e prendi che la regina "prende" questi campi

inserisci qui la descrizione dell'immagine

potresti semplicemente creare un array bidimensionale e "contrassegnare" tutti i campi che una regina attacca. Quindi posiziona l'altro (dal centro del tabellone), contrassegna i campi rimanenti e così via ... finché non corri su campi o regine.

Questo è ovviamente un approccio molto semplificato, poiché se posizionato in modo scorretto, raccolgo il numero massimo di regine che varia.

Hmm, ho trovato anche questo - problema con 8 regine.


All'inizio ho proposto questo esatto algoritmo, ma considera che non sei sicuro che se prendi questo approccio e finisci con nessun posto dove mettere la tua ultima regina che hai davvero determinato che è impossibile. Hai eliminato solo quella particolare disposizione. Questa è sostanzialmente un'applicazione dell'euristico vicino più vicino.
Intervistato

@Interviewee - Sì, lo so. Questo è solo qualcosa a cui ho pensato dalla cima della mia testa. Come detto, è un problema interessante e probabilmente potrebbe essere migliorato, ma alle 4 del mattino (qui) sono troppo pigro per pensare. A proposito, com'è andata l'intervista?
Torre

Intervista, questa è l'idea giusta. La parte che manca è che se scopri che non c'è posto per l'ultima regina, fai il backup e provi una posizione diversa per la penultima. Se non c'è posto per quella regina che consenta il posizionamento dell'ultima regina, fai un backup di un altro livello e provi un posto diverso per la terza fino all'ultima regina, e così via.
Caleb,

Mi piace che il tuo avatar sia un pezzo degli scacchi :)
Warren,

0

Fondamentalmente, l'algoritmo backtrack funziona in questo modo:

  1. Crea un array X per Y. Imposta tutti i quadrati su vuoti.

  2. Imposta il conteggio regina a zero.

  3. Imposta la tua posizione attuale su (1,1)

  4. Vedi se riesci a mettere una regina nella posizione attuale.

  5. Se è possibile, impostare Array (X, Y) su regina, incrementare il conteggio regina. Se hai piazzato tutta la regina, fermati , hai una soluzione.

  6. Se la posizione corrente non è (X, Y), incrementare la posizione corrente e andare al passaggio 4.

  7. Trova la regina nell'ultima posizione (quella che arriva per ultima nell'ordine in cui aumenti le posizioni). Imposta la posizione corrente sulla posizione di quella regina, rimuovila e diminuisci il conteggio della regina.

  8. Se il conteggio della regina è zero, fermati , non c'è soluzione.

  9. Incrementa la posizione corrente.

  10. Vai al passaggio 4.


In questa descrizione l'algoritmo non esegue correttamente il backtracking: rimuove solo l'ultima regina posizionabile; rischi di non provare mai regine precedenti in altre posizioni.
Kasper van den Berg,

@KaspervandenBerg L'algoritmo torna indietro correttamente. Risponderei direttamente alle tue critiche, ma sinceramente non riesco a capirlo. Non so cosa intendi per "ultima regina collocabile". Rimuoverà solo l'ultima regina piazzata, ma qualsiasi regina può diventare l'ultima regina piazzata una volta che le regine piazzate dopo che sono state rimosse. Tornerà indietro per quanto necessario, rimuovendo le regine al contrario dell'ordine in cui sono state posizionate.
David Schwartz,

0

Aggiungendo alle altre risposte: la creazione di un array bidimensionale complica solo il codice.

Hai solo bisogno di un vettore di dimensione 8 per una scacchiera normale. O 8 + 1 se come C 1 ° posizione è 0, solo per semplificare il codice, e gestire 1-8 e non 0-7.

Se pensi che x sia la tua posizione nell'array e y sia il contenuto della posizione. es. board [1] = 8 significa che la prima regina è a [1,8].

In questo modo, devi solo verificare la convalida delle colonne.

A tempo di facoltà, mi sono imbattuto in un libro molto vecchio (anni '60?), Sugli algoritmi implementati in Dartmouth BASIC, che ha implementato il problema delle 8 regina usando meno memoria possibile (essendo così vecchio, ha senso).

Per quanto mi ricordo, ha usato l'idea vettoriale e essenzialmente ha forzato tutte le posizioni nella scheda con due cicli FOR. Per verificare la validità della posizione, ha usato un terzo ciclo, un ciclo WHILE in ciascuna posizione torna indietro nel vettore e verifica la presenza di un numero uguale o una formula che utilizza un'operazione tangente per verificare le diagonali.

Purtroppo, ho perso la traccia di quel libro ...

Detto algoritmo ha trovato tutte le soluzioni per il problema n-queen.


0

Se devi solo scrivere un algoritmo per determinare se esiste una tale disposizione, allora guarda la ricerca esistente:
Otto regine su Wikipedia .

Puoi banalmente restituire false se N> min (X, Y).
Dopo aver letto quella pagina, sai di restituire vero se N <= min (X, Y) e 2, 3! = Min (X, Y).

Che lascia 2, 3 == min (X, Y) e N <= min (X, Y).

Bene, se N <min (X, Y), trovare una soluzione è banale.
Se N == min (X, Y), esiste una soluzione solo se max (X, Y)> N.

f(X, Y, N)
    if X < Y => f(Y, X, N)
    if Y > N => false
    => (Y < N) or (Y != 2 and Y != 3) or (X > N)

0

Ovviamente non c'è soluzione se N> min (X, Y). Altrimenti, puoi facilmente dimostrare che non esiste una soluzione per N = X = Y = 2, N = X = Y = 3. Per tutti gli altri casi sembra esserci una soluzione. Il numero di soluzioni sembra aumentare man mano che N cresce.

Puoi trovare una soluzione attraverso una ricerca esaustiva con backtracking: metti una regina nella prima fila, colonna 1. Metti una regina nella seconda fila, nella prima colonna che la regina nella riga 1 non può raggiungere. Metti una regina nella seconda fila ecc. Se una regina non può essere messa nella riga k, la rimuovi e sposti la regina nella riga k-1 nella successiva posizione non occupata.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.