N Queens, X by Y Board Decision Problem Interview Question


10

On m'a posé la question suivante dans une interview aujourd'hui et j'y pense depuis. Je n'ai pas pu y répondre et n'ai pas pu trouver de solution en ligne.

Étant donné un échiquier de dimensions X par des reines Y et N, déterminez s'il est possible d'agencer ces reines sur le plateau de sorte qu'elles ne puissent pas s'attaquer.

Une carte 2 x 3 avec 2 reines a une solution, donc l'algorithme retournerait vrai:

Q . .
. . Q

Je recherche une approche de programmation pour ce puzzle, pas seulement des moyens de le résoudre sur papier, par exemple.


La meilleure première recherche est certainement une option, tout comme d'autres heuristiques de recherche
Jason

2
nominé pour l'une des pires questions d'entrevue jamais - à moins que le logiciel sur lequel ils travaillent repose sur des solutions de retour en arrière, auquel cas c'est totalement pertinent
Steven A. Lowe

1
Pour être honnête, l'intervieweur a dit que c'était simplement une sorte de crédit supplémentaire. Le reste de l'entretien était assez légitime à l'OMI. J'étais juste curieux.
Interviewé le

C'était peut-être un test pour faire une simulation avec retour en arrière ou (penser à trouver) une solution O (1) en utilisant les faits énoncés par Caleb dans sa réponse. La capacité de programmer des choses simples n'est pas tout ce dont on a besoin dans le travail.
Sopel

les devoirs sont explicitement hors de portée ici.
jwenting

Réponses:


16

Ce n'est pas (IMO) un problème très intéressant du point de vue de la programmation. Vous pouvez trouver un algorithme récursif qui essaie tous les arrangements, quelque chose comme ceci:

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

Si vous pensez un peu au problème, vous vous rendrez compte qu'il n'y a aucun moyen de placer N reines sur une planche où X <N ou Y <N car cela nécessiterait qu'au moins deux reines se retrouvent dans le même rang ou fichier, et ils s’attaqueraient donc mutuellement. Si vous lisez le problème des n-reines, vous apprendrez rapidement qu'il est toujours possible de placer N reines sur une carte NxN pour N> 3. Maintenant, nous savons que la réponse est NON pour (X <N ou Y <N) et OUI pour (X> = N et Y> = N, N> 3). Il ne reste que les cas particuliers:

  • N = 1 (OUI)
  • N = 2 (OUI pour X> = 2 et Y> 2 ou vice versa)
  • N = 3 (OUI pour X> = 3 et Y> 3 ou vice versa)

Alors maintenant, notre belle fonction récursive devient une fonction simple qui compare simplement N à X et Y et renvoie un résultat standard. C'est génial du point de vue des performances, car vous pouvez obtenir une réponse en temps constant. Ce n'est pas si génial du point de vue de la programmation parce que vous vous rendez compte, à ce stade, que la question est vraiment plus sur la façon dont vous pouvez résoudre des énigmes que sur votre capacité à écrire une fonction récursive.

(Et garçon oh garçon, j'espère vraiment que je n'ai pas fait une erreur stupide dans ma réponse de 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.En fait, je pense que l'intervieweur attendait cette solution O (1) car elle est finalement meilleure et pas évidente pour beaucoup de gens. Le problème de la reine nxn est dans tous les cours de programmation comme un exercice de récursivité - beaucoup de gens ne réfléchiront pas plus profondément en revoyant ce problème.
Sopel

4

Si l'intervieweur vous avait demandé d'écrire le code du problème, je pense que ce n'est pas juste. L'algorithme nécessite du travail. Cependant, si l'idée était de montrer à l'enquêteur les classes, les méthodes ou certains concepts que vous auriez besoin d'utiliser ou quelque chose de similaire, alors cela pourrait être une bonne question.

Le problème est un problème informatique classique et est discuté dans de nombreux livres de ce type. Une excellente explication, avec animation et 12 solutions différentes avec du code peut être trouvée ici:

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

Le code peut également être trouvé ici: http://www.codeproject.com/KB/java/EightQueen.aspx

Ne vous sentez pas mal à ce sujet, comme je l'ai dit, ce n'est pas facile.


0

C'est plus un commentaire vraiment, mais ça ne rentre pas dedans ...

Un échiquier a 8x8 cases, ni plus ni moins (ces questions m'ennuient toujours avec cette approche d'un échiquier personnalisé).

Mais de toute façon, si vous avez un échiquier x * y, et n reines et que la reine "prend" ces champs

entrez la description de l'image ici

pourriez-vous simplement créer un tableau bidimensionnel et "signaler" tous les champs qu'une seule reine attaque. Ensuite, placez l'autre (du milieu du plateau), marquez les champs restants, etc. jusqu'à ce que vous exécutiez l'un des champs ou des reines.

Il s'agit bien sûr d'une approche très simplifiée, car si elle était positionnée de manière incorrecte, je suppose que le nombre maximum de reines varierait.

Hmm, je viens de trouver cela aussi - 8 problèmes de reines.


J'ai proposé cet algorithme exact au début, mais considérez que vous n'êtes pas assuré que si vous adoptez cette approche et que vous vous retrouvez sans aucun endroit pour mettre votre dernière reine que vous avez vraiment déterminé que c'est impossible. Vous avez seulement éliminé cet arrangement particulier. Il s'agit essentiellement d'une application de l'heuristique du plus proche voisin.
Interviewé le

@Interviewee - Oui, je sais. C'est juste quelque chose auquel j'ai pensé du haut de ma tête. Comme dit, c'est un problème intéressant et pourrait probablement être amélioré, mais à 4h du matin (ici), je suis juste trop paresseux pour penser. Au fait, comment s'est passée l'interview?
Tour

@Interviewee, c'est la bonne idée. La partie qui manque, c'est que si vous découvrez qu'il n'y a pas de place pour la dernière reine, vous sauvegardez et essayez une position différente pour l'avant-dernière reine. S'il n'y a pas de place pour cette reine qui permet le placement de la dernière reine, vous sauvegardez un autre niveau et essayez un endroit différent pour la troisième à la dernière reine, et ainsi de suite.
Caleb

J'aime que votre avatar soit une pièce d'échecs :)
warren

0

Fondamentalement, l'algorithme de retour arrière fonctionne comme ceci:

  1. Créez un tableau X par Y. Réglez tous les carrés sur vide.

  2. Réglez le nombre de reine à zéro.

  3. Réglez votre position actuelle sur (1,1)

  4. Voyez si vous pouvez placer une reine dans la position actuelle.

  5. Si vous le pouvez, définissez Array (X, Y) sur queen, augmentez le nombre de reine. Si vous avez placé toute la reine, arrêtez , vous avez une solution.

  6. Si la position actuelle n'est pas (X, Y), incrémentez la position actuelle et passez à l'étape 4.

  7. Trouvez la reine dans la dernière position (celle qui vient en dernier dans l'ordre où vous augmentez les positions). Définissez la position actuelle sur la position de cette reine, supprimez-la et décrémentez le nombre de reine.

  8. Si le nombre de reines est nul, arrêtez , il n'y a pas de solution.

  9. Incrémentez la position actuelle.

  10. Passez à l'étape 4.


Dans cette description, l'algorithme ne revient pas en arrière correctement: il supprime uniquement la dernière reine placable; vous risquez de ne jamais essayer des reines antérieures à d'autres positions.
Kasper van den Berg

@KaspervandenBerg L'algorithme revient correctement en arrière. Je répondrais directement à vos critiques, mais honnêtement, je ne peux pas les comprendre. Je ne sais pas ce que vous entendez par "dernière reine placable". Il n'enlèvera que la dernière reine placée, mais n'importe quelle reine peut devenir la dernière reine placée une fois que les reines placées après son retrait. Il reviendra en arrière autant que nécessaire, supprimant les reines dans le sens inverse de l'ordre où elles ont été placées.
David Schwartz

0

Ajout aux autres réponses: la création d'un tableau bidimensionnel ne fait que compliquer le code.

Vous avez juste besoin d'un vecteur de taille 8 pour un échiquier ordinaire. Ou 8 + 1 si, comme C, la 1ère position est 0, seulement pour simplifier le code, et traiter 1-8 et non 0-7.

Si vous pensez que x est votre position dans le tableau, et y le contenu de la position. Par exemple, la planche [1] = 8 signifie que la première reine est à [1,8].

De cette façon, il vous suffit de vérifier la validation des colonnes.

À la faculté, je suis tombé sur un très vieux livre (des années 60?), Sur les algorithmes implémentés dans Dartmouth BASIC, qui implémentait le problème des 8 reines en utilisant le moins de mémoire possible (étant aussi vieux, cela a du sens).

Pour autant que je m'en souvienne, il a utilisé l'idée de vecteur, et il a essentiellement forcé toutes les positions de la carte avec deux cycles FOR. Pour vérifier la validité de la position, il a utilisé une troisième boucle, un cycle WHILE dans chaque position revient dans le vecteur et vérifie un nombre égal ou une formule utilisant une opération tangente pour vérifier les diagonales.

Malheureusement, j'ai perdu la trace de ce livre ...

Cet algorithme a trouvé toutes les solutions au problème des n-queen.


0

Si vous n'avez qu'à écrire un algorithme pour déterminer si un tel arrangement existe, alors regardez la recherche existante:
Puzzle de huit reines sur Wikipédia .

Vous pouvez renvoyer trivialement faux si N> min (X, Y).
Après avoir lu cette page, vous savez retourner vrai si N <= min (X, Y) et 2, 3! = Min (X, Y).

Ce qui laisse 2, 3 == min (X, Y) et N <= min (X, Y).

Eh bien, si N <min (X, Y), trouver une solution est trivial.
Si N == min (X, Y), il n'y a de solution que si 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

Il n'y a évidemment pas de solution si N> min (X, Y). Sinon, vous pouvez facilement montrer qu'il n'y a pas de solution pour N = X = Y = 2, N = X = Y = 3. Pour tous les autres cas, il semble y avoir une solution. Le nombre de solutions semble augmenter à mesure que N croît.

Vous pouvez trouver une solution grâce à une recherche exhaustive avec retour en arrière: Mettez une reine dans la première rangée, colonne 1. Mettez une reine dans la deuxième rangée, dans la première colonne que la reine dans la rangée 1 ne peut pas atteindre. Mettez une reine dans la deuxième rangée, etc. Si une reine ne peut pas être placée dans la rangée k, alors vous la retirez et déplacez la reine dans la rangée k-1 dans la position inoccupée suivante.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.