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

Langage Java Discussion :

Problème de N-Reine


Sujet :

Langage Java

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    127
    Détails du profil
    Informations personnelles :
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations forums :
    Inscription : Avril 2005
    Messages : 127
    Par défaut Problème de N-Reine
    Bonjour.

    J'ai fait une classe permettant de placer n reines sur un échiquier sans qu'elles se menacent. J'ai voulu faire la méthode qui place toute les reines de manière récursive.

    Ma fonction utilise le backtracking c'est à dire que si je ne peux pas mettre une reine sur la ligne sans qu'elle soit prise je réévalue le coup précédent.

    Voici ma méthode auriez vous une idée afin de l'optimiser ....

    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
     
    public void justDoIt(int ligne,int colonne)	{
    		test++;
    		int tmp_colonne=0;
    		int tmp_ligne=0;
     
    		/* Si on peut mettre la reine aux indices données en paramètre on la met */
    		if(canPutLady(ligne,colonne))	{
     
    			putLady(ligne,colonne);
     
    			etape++;
    			System.out.println("************** ETAPE "+etape+" **************\n************** BACK "+back+" **************");
    			System.out.println(this);
     
    			/* Si ce n'est pas la dernière reine que l'on met on continue */
    			if(ligne+1<taille)	{
    				justDoIt(ligne+1,0);
    			}
     
    			else 
    				return;
     
    		}
     
    		else	{
    			/* Si l'indice de la colonne donnée en paramètre est inférieur à la taille-1 de l'échiquier
    			on peut essayer de voir si la reine peut aller sur la colonne de droite */
    			if(colonne+1<taille)	{
    				justDoIt(ligne,colonne+1);
    			}
     
    			/*On ne peut pas mettre la reine dans la ligne mis en paramètre avec la configuration de l'échiquier actuel */
    			else	{
     
    				/* Si la reine de la ligne du dessus n'est pas sur l'avant dernière colonne on enlève cette reine
    				et on essaie de la placer sur la première colonne suivant possible */
    				if((echiquier[ligne-1]+1)<taille)	{
    					tmp_colonne=(echiquier[ligne-1]+1);
    					echiquier[ligne-1]=-1;
    					etape++;
    					back++;
    					System.out.println("************** ETAPE "+etape+" **************\n************** BACK "+back+" **************");
    					System.out.println(this);
    					justDoIt(ligne-1,tmp_colonne);
    				}
     
    				/* Sinon on recule encore d'une ligne */
    				else	{
    					/* On prend la ligne du dessus et on vérifie que la colonne n'est pas la dernière */
    					tmp_colonne=echiquier[ligne-1];
    					tmp_ligne=ligne-1;
    					echiquier[ligne-1]=-1;
    					etape++;
    					back++;
    					System.out.println("************** ETAPE "+etape+" **************\n************** BACK "+back+" **************");
    					System.out.println(this);
     
    					/* Si ce n'est pas la dernière colonne on essaie de replacer la reine qu'on enlève à partir de la colonne suivante */
    					if(tmp_colonne+1<=taille)	{
    						justDoIt(tmp_ligne-1,echiquier[tmp_ligne-1]+1);
    					}
     
    					/* Sinon on repart de la première colonne */
    					else	{
    						justDoIt(ligne-1,0);
    					}
    				}
    			}
    		}
    	}

  2. #2
    Membre expérimenté
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    194
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Juin 2006
    Messages : 194
    Par défaut
    De ce qu'on voit, je peux te conseiller de supprimer les traces que tu imprimes sur la console, la différence sera flagrante. Si c'est la clarté du code, tu pourrais utiliser if/elseif plutôt que d'imbriquer les if/else.

    Bon pour passer aux choses sérieuses j'ai l'impression que ce sont en fait tes méthodes putLady() et canPutLady() qu'il faudrait optimiser. Lorsque tu passes à la pièce suivante, tu fais une récursion en incrémentant simplement la ligne ou la colonne.

    Je te propose de représenter ton échiquer avec un tableau de boolean de taille 64. Lorsque tu ajoutes une reine, passes à false toutes les cellules qui ne peuvent plus admettre de pièce (la technique est très proche du crible d'Erathostène). Puis passes à la pièce suivante en cherchant la première cellule à true (décidément, ça ressemble vraiment au crible d'Erathostène )

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    127
    Détails du profil
    Informations personnelles :
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations forums :
    Inscription : Avril 2005
    Messages : 127
    Par défaut
    En fait le problème est que je dois faire cela en utilisant la récursivité mais ce que je fais dans ma méthode n'en est pas vraiment une mais je n'arrive pas du tout à voir comment faire. Parce que avec ma méthode dès qu'il y a trop de calcul bah la pile ne supporte pas ^^.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Exception in thread "main" java.lang.StackOverflowError
           at Echiquier.justDoIt(Echiquier.java:100)
           at Echiquier.justDoIt(Echiquier.java:100)
           at Echiquier.justDoIt(Echiquier.java:100)
           ... etc...

  4. #4
    Membre éclairé

    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 418
    Par défaut
    Salut.

    Citation Envoyé par @po©alypse
    je dois faire cela en utilisant la récursivité mais ce que je fais dans ma méthode n'en est pas vraiment une
    Effectivement...
    Si je comprends bien ton code, aucune de tes boucles dans la fonction récursive ne se termine avant la résolution complète du problème (quand on arrive à la fin de l'échiquier). Forcément, la mémoire explose...

    Citation Envoyé par had35
    Lorsque tu passes à la pièce suivante, tu fais une récursion en incrémentant simplement la ligne ou la colonne.
    Dans tes if, tu ne modifies que les paramètres (et ton échiquier, bien entendu).
    Si je reprends ton code :
    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    public void justDoIt(int ligne,int colonne)	{
    		test++;
     
    		int ligneFin = 0;
    		int colonneFin = 0;
     
    		boolean modifEchiquier = false;
     
    		/* Si on peut mettre la reine aux indices données en paramètre : */
    		if(canPutLady(ligne,colonne))	{
    			ligneFin = ligne;
    			colonneFin = colonne;
     
    			modifEchiquier = true;
    		}
     
    		/*On ne peut pas mettre la reine dans la ligne mis en paramètre avec la configuration de l'échiquier actuel */
    		 else {
    			/* Si l'indice de la colonne donnée en paramètre est inférieur à la taille-1 de l'échiquier
    			on peut essayer de voir si la reine peut aller sur la colonne de droite */
    			if(colonne+1<taille)	{
    				colonneFin ++;
    				ligneFin = ligne;
    			}			
     
    			/* Si la reine de la ligne du dessus n'est pas sur l'avant dernière colonne on enlève cette reine
    			et on essaie de la placer sur la première colonne suivante possible */			
    			else if ((echiquier[ligne-1]+1)<taille) {
    				colonneFin = echiquier[ligne-1] + 1;
    				ligneFin --;
    				echiquier[ligne-1] = -1;
     
    				back++;
    				modifEchiquier = true;
    				}
     
    				/* Sinon on recule encore d'une ligne */
    				else	{
    					/* On prend la ligne du dessus et on vérifie que la colonne n'est pas la dernière */
    					int colonne_tmp = 0;
    					colonne_tmp = echiquier[ligne-1];
     
    					echiquier[ligne-1]=-1;
     
    					back++;					
    					modifEchiquier = true;
     
    					/* Si ce n'est pas la dernière colonne on essaie de replacer la reine qu'on enlève à partir de la colonne suivante */
    					if((colonne_tmp+1) <= taille)	{
    						ligneFin = ligne -2;
    						colonneFin = echiquier[ligneFin] + 1;
    					}
     
    					/* Sinon on repart de la première colonne */
    					else	{
    						ligneFin = ligne-1;
    						colonneFin = 0;
    					}
    				}
    			}
     
    		/* Si ce n'est pas la dernière reine que l'on met on continue */
    		if(((ligne+1) < taille) && (colonneFin != -1) && (ligneFin != -1))	{
    			etape ++;
     
    			System.out.println("************** ETAPE "+etape+" **************\n************** BACK "+back+" **************");
     
    			if (modifEchiquier) System.out.println(this);
     
    			justDoIt(ligne+1,0);
    		}
     
    	}
    Remarque aussi que ton seul critère d'arrêt est quand tu arrives à la fin de l'échiquier. Je ne connais pas le problème des n-reines, mais es-tu sûr que dans la solution, il y ait une reine sur la dernière ligne ??? Parce que sinon, tu risques de boucler indéfiniment, ou d'avoir des erreurs !!
    Dans le code que j'ai mis, si on ne rentre dans aucune condition de (dé)placement de reine, la fonction n'est pas rappelée. Cela dit, je ne suis pas sûr que ça ne boucle pas non plus...

    Il est très tard, et je risque d'avoir dit quelques énormité. J'éspère quand même que ça te sera utile.
    A+

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    127
    Détails du profil
    Informations personnelles :
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations forums :
    Inscription : Avril 2005
    Messages : 127
    Par défaut
    Voici ma classe entière :

    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
     
     
    /**
     * Echiquier.java<br />
     *
     * Version du 04/10/2006<br />
     */
     
     
     
     
    public class Echiquier 	{
       private int[] echiquier;
       private int taille;
       private int test=0;
       private int etape=0;
       private int back=0;
       private String msg="";
     
     
    	/**
             * Constructeur créant un tableau permettant de gérer l'emplacement des dames
             * @param n Taille de l'échiquier
             */
    	public Echiquier(int n)	{
    		echiquier=new int[n];
    		taille=n;
     
    		init();
    	}
     
     
     
    	/**
             * Méthode permettant d'initialiser l'échiquier avec aucune reine
             */
    	public void init()	{
    		for(int i=0;i<taille;i++)	{
    			echiquier[i]=-1;
    		}
    	}
     
     
     
    	/**
             * Méthode permettant de mettre sur l'échiquier une reine aux coordonnées données en paramètre
             * @param ligne Numéro de la ligne ou l'on souhaite mettre la reine
             * @param colonne Numéro de la colonne ou l'on souhaite mettre la reine
             */
    	public void putLady(int ligne,int colonne)	{
    		echiquier[ligne]=colonne;
    	}
     
     
     
    	/**
             * Méthode permettant de savoir si l'on peut mettre sur l'échiquier une reine aux coordonnées données en paramètre
             * @param ligne Numéro de la ligne ou l'on souhaite mettre la reine
             * @param colonne Numéro de la colonne ou l'on souhaite mettre la reine
             * @return si la dame peut être mise
             */
    	public boolean canPutLady(int ligne,int colonne)	{
          return (!isInColumn(colonne) && !isInDiagonal(ligne,colonne));
       }
     
     
     
    	/**
             * Méthode permettant de remplir l'échiquier en utilisant le backtracking
             * @param ligne Numéro de la ligne ou l'on souhaite mettre la reine
             * @param colonne Numéro de la colonne ou l'on souhaite mettre la reine
             */
    	public void justDoIt(int ligne,int colonne)	{
     
    		test++;
    		int tmp_colonne=0;
    		int tmp_ligne=0;
     
    		/* Si on peut mettre la reine aux indices données en paramètre on la met */
    		if(canPutLady(ligne,colonne))	{
     
    			putLady(ligne,colonne);
     
    			etape++;
    			System.out.println("************** ETAPE "+etape+" **************\n************** BACK "+back+" **************");
    			System.out.println(this);
     
    			/* Si ce n'est pas la dernière reine que l'on met on continue */
    			if(ligne+1<taille)	{
    				justDoIt(ligne+1,0);
    			}
     
    			else	{
    				return;
    			}
     
    		}
     
    		else	{
    			/* Si l'indice de la colonne donnée en paramètre est inférieur à la taille-1 de l'échiquier
    			on peut essayer de voir si la reine peut aller sur la colonne de droite */
    			if(colonne+1<taille)	{
    				justDoIt(ligne,colonne+1);
    			}
     
    			/*On ne peut pas mettre la reine dans la ligne mis en paramètre avec la configuration de l'échiquier actuel */
    			else	{
     
    				/* Si la reine de la ligne du dessus n'est pas sur l'avant dernière colonne on enlève cette reine
    				et on essaie de la placer sur la première colonne suivant possible */
    				if((echiquier[ligne-1]+1)<taille)	{
    					tmp_colonne=(echiquier[ligne-1]+1);
     
    					echiquier[ligne-1]=-1;
     
    					etape++;
    					back++;
     
    					System.out.println("************** ETAPE "+etape+" **************\n************** BACK "+back+" **************");
    					System.out.println(this);
     
    					justDoIt(ligne-1,tmp_colonne);
    				}
     
    				/* Sinon on recule encore d'une ligne */
    				else	{
    					/* On prend la ligne du dessus et on vérifie que la colonne n'est pas la dernière */
    					tmp_colonne=echiquier[ligne-1];
    					tmp_ligne=ligne-1;
     
    					echiquier[ligne-1]=-1;
     
    					etape++;
    					back++;
    					System.out.println("************** ETAPE "+etape+" **************\n************** BACK "+back+" **************");
    					System.out.println(this);
     
    					/* Si ce n'est pas la dernière colonne on essaie de replacer la reine qu'on enlève à partir de la colonne suivante */
    					if(tmp_colonne+1<=taille)	{
    						justDoIt(tmp_ligne-1,echiquier[tmp_ligne-1]+1);
    					}
     
    					/* Sinon on repart de la première colonne */
    					else	{
    						justDoIt(ligne-1,0);
    					}
    				}
    			}
    		}
    	}
     
     
     
    	/**
             * Méthode permettant de savoir si une rein est déjà poser sur la colonne passé en paramètre
             * @param colonne Numéro de la colonne ou l'on souhaite mettre la reine
             * @return Si une reine est déjà sur la colonne mis en paramètre
             */
    	public boolean isInColumn(int colonne)	{
    		for(int i=0;i<taille;i++)	{
    			if(echiquier[i]==colonne)	{
    				return true;
    			}
    		}
    		return false;
    	}
     
     
     
    	/**
             * Méthode permettant de savoir si une rein est déjà poser sur la diagonal de la case dont les coordonnées sont passé en paramètre
             * @param ligne Numéro de la ligne de la case
             * @param colonne Numéro de la colonne de la case
             * @return Si une reine est déjà sur la diagonale de la case
             */
    	public boolean isInDiagonal(int ligne,int colonne)	{
    		boolean existe=false;
     
    		for(int i=0;i<taille && existe==false;i++)	{
    			if(echiquier[i]!=-1)	{
    				int diff_ligne=ligne-i;
    				int diff_colonne=colonne-echiquier[i];
     
    				if(Math.abs(diff_ligne)==Math.abs(diff_colonne))
    					existe=true;
    			}
    		}
     
    		return existe;
    	}
     
     
     
    	/**
             * Méthode permettant l'affichage en mode texte de l'échiquier
             * @return La chaîne de caractère contenant tout l'échiquier
             */
    	public String toString()	{
    		String s="";
     
    		for(int i=0;i<taille;i++)	{
    			for(int j=0;j<taille;j++)	{
    				if(echiquier[i]!=-1 && echiquier[i]==j)	{
    					s+="[R]";
    				}
    				else	{
    					s+="[*]";
    				}
    			}
    			s+="\n";
    		}
     
    		return s;
    	}
     
     
     
    	/** Main **/
    	public static void main(String [] argv)	{
    		Echiquier echiquier=new Echiquier(8);
    		echiquier.justDoIt(0,0);
     
    	}
     
    }
    et dans la solution il y a bien une reine dans la dernière ligne mais si je passe par exemple dans le main

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Echiquier echiquier=new Echiquier(12);
    echiquier.justDoIt(0,2);
    Et bien j'ai l'erreur ^^. Ce que je voudrai c'est toujours garder la méthode de retour en arrière si je n'ai pas de solution sur la ligne actuelle tout en restant en récursif...

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    31
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 31
    Par défaut
    Une idée pourrait être de transformer ton algo récursif en algo itératif, en utilisant une pile. Ca évitera de sauvegarder tout le contexte de ta fonction à chaque appel. A la place tu ne sauvegardes sur la pile que les données nécessaires à la reprise de l'algo en cas de backtracking.

  7. #7
    Membre éclairé

    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2005
    Messages : 418
    Par défaut
    T'as essayé avec ma méthode ?

    Citation Envoyé par @po©alypse
    je voudrai c'est toujours garder la méthode de retour en arrière si je n'ai pas de solution sur la ligne actuelle
    Là encor, si la dernière dame ne peut pas être affectée à la dernière colonne de la dernière ligne, tu vas à chaque fois revenir en arrière, non ? (et donc bouclé à l'infini...)
    Citation Envoyé par loicdvi
    A la place tu ne sauvegardes sur la pile que les données nécessaires à la reprise de l'algo en cas de backtracking.
    Perso, c'est plutôt comme ça que je ferais...

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    127
    Détails du profil
    Informations personnelles :
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations forums :
    Inscription : Avril 2005
    Messages : 127
    Par défaut
    Citation Envoyé par marchand_de_sable
    T'as essayé avec ma méthode ?.
    Non enfin pas encore.


    Citation Envoyé par loicdvi
    Une idée pourrait être de transformer ton algo récursif en algo itératif, en utilisant une pile. Ca évitera de sauvegarder tout le contexte de ta fonction à chaque appel. A la place tu ne sauvegardes sur la pile que les données nécessaires à la reprise de l'algo en cas de backtracking.
    Je dois le faire en récursif uniquement c'est de l'IA en fait, on doit le faire en récursif et faire comme si c'était une personne qui mettait une à une les reines d'ou le backtracking.

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    31
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 31
    Par défaut
    Citation Envoyé par @po©alypse
    Je dois le faire en récursif uniquement c'est de l'IA en fait, on doit le faire en récursif et faire comme si c'était une personne qui mettait une à une les reines d'ou le backtracking.
    Le fait de rendre ton algo iteratif en utilisant une pile ne changera pas le fait que c'est une programmation récursive. Tu me suis ?

    En fait ce que je veux dire c'est que tu veux un algo récursif, pas de pb. Le problème dans ton implantation c'est que si tu fait des appels récursifs de ta fonction, à chaque appel le contexte d'exécution de la fonction est sauvegardé sur la pile (du système). Tu vas donc empiler à chaque appel un grand nombre de données, et c'est ce qui provoque le débordement de pile au bout d'un moment.
    Pour éviter ça la solution est de faire de la récursivité mais avec une implantation itérative. Pour cela on utilise une pile (que tu déclares explicitement dans ta classe). Chaque appel récursif dans l'implantation récursive va alors correspondre à l'empilement par tes soins (et donc c'est toi qui choisis ce que tu veux empiler) des données à sauvegarder. Cela te permet de pouvoir retrouver l'état dans lequel tu étais avant l'appel récursif, au cas où tu backtrackerais.

    Avec cette méthode tu as toujours un algo récursif, mais implanté d'une façon itérative.

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    31
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 31
    Par défaut
    Sinon, tu peux aussi t'amuser à faire ton algo en Prolog ou en Lisp...

  11. #11
    Membre expérimenté
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    194
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Juin 2006
    Messages : 194
    Par défaut
    Je pense que ton approche ne permet pas de trouver de solution. Voici le code que j'ai testé chez moi en suivant à la lettre ton principe de backtracking :
    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
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
     
    public class NReines {
     
    	private int[] echiquier;
    	private final int largeur;
     
    	public NReines(int cote) {
    		echiquier = new int[largeur=cote];
    		Arrays.fill(echiquier, -1);
    	}
     
    	public void launch() {
    		for(int ligne=0; ligne<largeur;) {
    			ligne = put(ligne) + 1;
    			if(ligne == 0) {
    				System.out.println("L'algorithme actuel ne permet pas la résolution du problème des N-Reines");
    				return;
    			}
    		}
    	}
     
    	/**
             * Essaye de positionner une reine sur une ligne. Si aucune position n'est libre
             * sur la ligne courante, réévalue les décisions précédentes.
             * 
             * @param       lig
             * @return      la position de la dernière reine déplacée,
             *                      -1 si le problème n'a pas de solution
             */
    	int compteur;
    	protected int put(int lig) {
    		if( put(lig, echiquier[lig]+1) == -1 ) {
    			if(lig == 0)
    				return -1; //le problème n'a pas trouvé de solution
    			return put(lig-1); //on revient sur la ligne précédente
    		}
    		return lig;
    	}
     
    	/**
             * Place la reine sur la ligne demandée si la position n'est pas menacée par
             * une autre pièce
             * 
             * @param lig
             * @param col
             * @return      la colonne sur laquelle a été placée la reine,
             *                      -1 si elle n'a pas pu être placée
             */
    	protected int put(final int lig, int col) {
    		if(col > largeur) {
    			return -1; //la pièce ne peut pas être placée sur cette ligne
    		}
    		if( !canPut(lig, col, 1) ) {
    			return put(lig, ++col);
    		}
    		//System.out.println("Reine en " + (char)(col+'A') + lig);
    		return echiquier[lig] = col; //la pièce a été placée sur cette ligne
    	}
     
    	/**
             * Vérifie si la position demandée est libre en vérifiant les positions
             * potentiellement menaçantes sur toutes les lignes au-dessus (les seules à
             * être occupées).
             * 
             * @param lig   coordonnées de la position à tester
             * @param col   coordonnées de la position à tester
             * @param n             niveau d'évaluation, doit commencer à 1
             * @return
             */
    	protected boolean canPut(final int lig, final int col, int n) {
    		if(n > lig) {
    			return true;//la position est libre
    		}
    		System.out.println("lig : " + lig + " - " + "n : " + n);
    		if(echiquier[lig-n]==col || echiquier[lig-n]==col-n || echiquier[lig-n]==col+n) {
    			return false;//la position est menacée
    		}
    		return canPut(lig, col, ++n);
    	}
    }
    Je pense qu'il faut adopter une approche moins rigoureuse et tester des positions aléatoires.

  12. #12
    Membre Expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Par défaut
    Salut,

    En gros, le problème peut être vu comme un filtrage de permutations.

    Tu veux placer 8 reines, donc tu en places une sur la première ligne en position 1 ou 2 ou 3 ou 4 ou 5 ou 6 ou 7 ou 8.
    Ensuite tu en places une sur la deuxième ligne, parmis toutes les positions restantes etc...

    ça fait 8! permutations.

    Donc déjà si tu fais une méthode récursive qui te permet de calculer les permutations de 8 numéros, il suffit que tu rajoutes dans cette fonction le "TEST" qui te permet de savoir si une permutation est correcte, c'est-à-dire que les reines ne se menacent pas dans les autres directions, et voilà...

    De mémoire, je crois qu'il y a 72 solutions, non?

Discussions similaires

  1. 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, 16h38
  2. Mon premier programme en MFC: Problème de 8 reines
    Par Dũng chim dans le forum MFC
    Réponses: 0
    Dernier message: 16/12/2008, 16h50
  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, 16h45
  4. [Problème] Programme huit reines
    Par thegreatbato dans le forum C
    Réponses: 20
    Dernier message: 04/05/2006, 23h04
  5. problème des N reines récursif
    Par duvi dans le forum C++
    Réponses: 7
    Dernier message: 20/02/2006, 14h45

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