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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  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 : 40
    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.

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, 15h38
  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, 15h50
  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] Programme huit reines
    Par thegreatbato dans le forum C
    Réponses: 20
    Dernier message: 04/05/2006, 22h04
  5. 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