IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

MATLAB Discussion :

Problème des n-reines


Sujet :

MATLAB

  1. #1
    Membre habitué
    Homme Profil pro
    Ingénieur opto-électronique
    Inscrit en
    Avril 2010
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur opto-électronique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2010
    Messages : 129
    Points : 157
    Points
    157
    Par défaut Problème des n-reines
    Bonjour,
    J'ai décidé de m'initier à la programmation par contraintes et j'ai voulu essayer de réaliser un programme qui trouverait une solution au problème des reines, par backtracking.

    Pour ceux qui ne connaitraient pas, le problème des reines consiste à placer N reines sur un équiquier de taille NxN sans qu'aucune ne soit menacée par les autres.

    J'ai tenté de résoudre ce problème avec un échiquier de taille 8x8, mais mon programme semble tourner en rond sans me donner de réponse et je ne comprends pas pourquoi.


    Mon programme:

    ligneok : Vérification qu'il n'y a aucune reine sur la ligne correspondant à la case étudiée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    function ok=ligneok(placement,position)
     
    if sum(placement==position)>=1
        ok=false;
    else
        ok=true;
    end
    Diagok : Vérification qu'il n'y a aucune reine sur les diagonales associées à la case étudiée:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    function ok=diagok(placement,p)
     
    n=length(placement);
    grille=zeros(n+1);
     
    for i=1:n
        grille (placement(i),i)=1;
    end
    grille(p,n+1)=1;
     
     
    for i=1:n
        %diagonale NO-SE
        if (i-placement(i)==n+1-p)
            ok=false;
            return
        end
        %diagonale SO-NE
        if (i+placement(i)==n+1+p)
            ok=false;
            return
        end
    end
     
    ok=true;
    Affichage du résultat:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function affichage(placement)
     
    n=length(placement);
    disp('solution :')
     
    grille=zeros(n);
    for i=1:n
        grille (placement(i),i)=1;
    end
    for i=1:n
        fprintf(1,'%i\t',grille(i,:));
        fprintf(1,'\n')
    end
    Algorithme de backtrack:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    function ok=positionvalide(placement,colonne)
     
        %fin de l'equiquier atteinte.
        if colonne==9
            affichage(placement);
            ok = true;
            return;
        end
     
        %cas général
        for position=1:9
            if ligneok(placement,position) && diagok(placement,position)
                placement=[placement position]
    %             pause()
                if positionvalide(placement, colonne+1)
                    ok=true;
                    return;
                end
            end
        end
        placement=placement(1:end-1);
        ok=false;
        return

    Main.m
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    colonne=1;  %initialisation
    placement=[];
     
    positionvalide(placement,colonne);

    dans l'algo de backtrack, j'ai volontairement laissé l'affichage de la ligne "placement=[placement position]" afin de voir l'évolution de la recherche, et je vois mon code tourner en rond avant de s'arrêter:
    placement =
    1 3 5 7 2 4
    placement =
    1 3 5 7 2 4 6
    placement =
    1 3 5 7 2 4 6
    placement =
    1 3 5 7 2 4
    placement =
    1 3 5 7 2 4 6
    placement =
    1 3 5 7 2 4 6

    Si quelqu'un savait me dire pourquoi mon programme tourne en rond alors que normalement avec la boucle "for" il ne devrait pas pouvoir tester plusieurs fois la même branche, cela m'arrangerait beaucoup.

    Mon programme n'étant quasiment pas commenté, n'hésitez pas à me poser des questions si vous ne saisissez pas ce que j'ai voulu faire.

    Merci d'avance !

  2. #2
    Membre émérite
    Avatar de Franck Dernoncourt
    Homme Profil pro
    PhD student in AI @ MIT
    Inscrit en
    Avril 2010
    Messages
    894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : PhD student in AI @ MIT
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2010
    Messages : 894
    Points : 2 464
    Points
    2 464
    Par défaut
    Il y avait un problème dans l'algorithme de backtrack, voici la version corrigée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    function ok=positionvalide(placement,colonne)
     
        %fin de l'equiquier atteinte.
        if colonne==9
            disp('ok');
            placement
            ok = true;
            return;
        end
     
        %cas général
        for position=1:8
            if ligneok(placement,position) && diagok(placement,position)
                placement_temp = [placement position];
                if positionvalide(placement_temp, colonne+1)
                    ok=true;
                    return;
                end
            end
        end
        placement=placement(1:end-1);
        ok=false;
        return

  3. #3
    Membre émérite
    Avatar de Franck Dernoncourt
    Homme Profil pro
    PhD student in AI @ MIT
    Inscrit en
    Avril 2010
    Messages
    894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : PhD student in AI @ MIT
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2010
    Messages : 894
    Points : 2 464
    Points
    2 464
    Par défaut coding style
    Note de coding style pour ligneok, mieux vaut écrire cela :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    function ok=ligneok(placement,position)
    ok=not(sum(placement==position)>=1);

  4. #4
    Rédacteur/Modérateur

    Avatar de Jerome Briot
    Homme Profil pro
    Freelance mécatronique - Conseil, conception et formation
    Inscrit en
    Novembre 2006
    Messages
    20 302
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Freelance mécatronique - Conseil, conception et formation

    Informations forums :
    Inscription : Novembre 2006
    Messages : 20 302
    Points : 52 882
    Points
    52 882
    Par défaut
    Citation Envoyé par FrankyRP Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    function ok=ligneok(placement,position)
    ok=not(sum(placement==position)>=1);
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    function ok=ligneok(placement,position)
    ok = sum(placement==position)<1;
    ou :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    function ok=ligneok(placement,position)
    ok = ~any(placement==position);
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    function ok=ligneok(placement,position)
    ok = all(placement~=position);
    Ingénieur indépendant en mécatronique - Conseil, conception et formation
    • Conception mécanique (Autodesk Fusion 360)
    • Impression 3D (Ultimaker)
    • Développement informatique (Python, MATLAB, C)
    • Programmation de microcontrôleur (Microchip PIC, ESP32, Raspberry Pi, Arduino…)

    « J'étais le meilleur ami que le vieux Jim avait au monde. Il fallait choisir. J'ai réfléchi un moment, puis je me suis dit : "Tant pis ! J'irai en enfer" » (Saint Huck)

  5. #5
    Membre émérite
    Avatar de Franck Dernoncourt
    Homme Profil pro
    PhD student in AI @ MIT
    Inscrit en
    Avril 2010
    Messages
    894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : PhD student in AI @ MIT
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2010
    Messages : 894
    Points : 2 464
    Points
    2 464
    Par défaut
    ah oui, je n'avais même pas lu la condition, c'est juste le branchement qui m'avait fait tilter

  6. #6
    Membre habitué
    Homme Profil pro
    Ingénieur opto-électronique
    Inscrit en
    Avril 2010
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur opto-électronique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2010
    Messages : 129
    Points : 157
    Points
    157
    Par défaut
    Merci pour ces commentaires, en effet ça fonctionne maintenant.
    Mais j'ai du mal à comprendre pourquoi :/

    Je m'étais planté sur le nombre de lignes, ça je comprends tout à fait, mais c'est le rôle de placement_temp que je ne suis pas sûr de comprendre.

    Si j'ai bien suivi, mettons que n reines soient placées.

    Ce que faisait mon programme:
    Il vérifie pour la n+1eme reine que le placement est possible, s'il ne l'est pas, il supprime cette n+1eme reine de la variable position, ce qui fait que ça tournait en rond.

    Ce que fait la version corrigée par Franck:
    Il vérifie pour la n+1eme reine que le placement est possible, et s'il ne l'est pas il supprime la n-eme reine, ce qui fait que l'on passera bien à la branche suivante.

    J'ai bon ?

  7. #7
    Membre émérite
    Avatar de Franck Dernoncourt
    Homme Profil pro
    PhD student in AI @ MIT
    Inscrit en
    Avril 2010
    Messages
    894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : PhD student in AI @ MIT
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2010
    Messages : 894
    Points : 2 464
    Points
    2 464
    Par défaut
    Le problème était que ton backtrack était trop tardif : regarde cette vversion, tu comprendras mieux. (simple déplacement de la ligne placement=placement(1:end-1); par rapport à ta version). J'avais utilisé placement_temp par simplicité.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    function ok=positionvalide(placement,colonne)
     
        %fin de l'equiquier atteinte.
        if colonne==9
            placement
            ok = true;
            return;
        end
     
        %cas général
        for position=1:8
            if ligneok(placement,position) && diagok(placement,position)
                placement=[placement position];
    %             pause()
                if positionvalide(placement, colonne+1)
                    ok=true;
                    return;
                end
                placement=placement(1:end-1);
            end
        end
     
        ok=false;
        return

  8. #8
    Membre habitué
    Homme Profil pro
    Ingénieur opto-électronique
    Inscrit en
    Avril 2010
    Messages
    129
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur opto-électronique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2010
    Messages : 129
    Points : 157
    Points
    157
    Par défaut
    OK je comprends mieux ! Merci pour ton aide !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Probléme des N-reines.
    Par Masshat dans le forum Prolog
    Réponses: 3
    Dernier message: 04/02/2013, 21h09
  2. Afficher toutes les solutions au problème des N-Reines
    Par pottiez dans le forum Télécharger
    Réponses: 0
    Dernier message: 30/11/2010, 15h38
  3. solution non récursive au problème des N reines
    Par patrick974 dans le forum Algorithmes et structures de données
    Réponses: 1
    Dernier message: 12/09/2008, 15h45
  4. problème des N reines récursif
    Par duvi dans le forum C++
    Réponses: 7
    Dernier message: 20/02/2006, 13h45

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo