Matrice, trajet

Apaachee Messages postés 261 Statut Membre -  
Apaachee Messages postés 261 Statut Membre -
Bonjour, j'ai quelques soucis à élaborer une fonction en Java, je m'explique...

Je possède une matrice du type

0 0 0 0 1 0 0
0 0 0 0 1 1 0
0 0 0 0 0 1 0
0 0 0 0 1 1 0
0 0 0 0 1 0 0
0 0 0 1 1 1 0
0 0 1 1 0 1 0
0 1 1 0 0 0 0

Enfin voila, les '1' forment un "parcours" dans ma matrice, parcours qui peut 'monter', descendre, aller à gauche ou droite, et ma fonction doit me permettre de savoir si le parcours des 1 relie le bord du haut au bord du bas de ma matrice.

Ca a priori l'air assez simple, mais je bloque vraiment sur la façon de faire.
Configuration: Windows XP
Firefox 3.5.5

8 réponses

  1. Pilow Messages postés 410 Statut Membre 71
     
    Bonjour

    Cela peut paraitre "simple" oui mais l'algo est quand même assez "embêtant" quand même !

    Je te conseil de regarder vers la récursivité.
    Imaginons tu ai ce tableau
    Tu pars du haut a gauche
    tu as une variable "ligne" qui désigne le nombre de caractere sur chaque ligne
    tu parcours ta première ligne et a chaque 1 que tu rencontre tu lance la fonction récursive ci-dessous
    Et tu boucle en recursif toujours

    Moi je l'avais fais en C et ça donnait un truc du genre :

    int ta_fonction()
    {
    if (tab[x + 1][y] && tab[x + 1][y] == '1')
    {
    if (x+1 = la dernière ligne de ton tableau)
    	SUCCESS !
    else
    	rappel ta fonction avec tes nouvelles coordonnées
    }
    
    else if (tab[x - 1][y] && tab[x - 1][y] == '1')
    {
    if (x-1 = la dernière ligne de ton tableau)
    	SUCCESS !
    else
    	rappel ta fonction avec tes nouvelles coordonnées
    }
    
    else if (tab[x][y - 1] && tab[x][y - 1] == '1')
    {
    	rappel ta fonction avec tes nouvelles coordonnées
    }
    else if (tab[x][y + 1] && tab[x][y + 1] == '1')
    {
    	rappel ta fonction avec tes nouvelles coordonnées
    }
    return (0);
    }


    Avec tout ca tu dois tester que tu n'est pas deja passé par cette case, pour éviter les boucles infinis
    0
  2. Groarh Messages postés 706 Statut Membre 185
     
    Hello !
    J'ai eu affaire à un problème similaier l'année dernière. J'avais une image monochrome (noir et blanc => 0 pour noir et 1 pour blanc) et il fallait écrire une fonction Java pour extraire des zones de pixels noirs contigus.

    Le prof nous avait montré une méthode non récursive basée sur une liste de points à parcourir. La liste contient des doublets (x, y) représentant les coordonnées des points mémorisés. Il faut aussi copier la matrice, car cette méthode exige qu'on la modifie.
    Mettons que la liste s'appelle L, et la copie de la matrice M.

    Je vais esayer d'être le plus clair possible :
    - on parcourt la première ligne de M pour trouver un 1, que l'on ajoute à L. C'est le point de départ.
    - boucle while :
    - pour chaque 1 dans L, on le met à 0 dans M et on regarde les voisins directs (gauche, droite, haut, bas) ; quand le voisin est à 1, on l'ajoute à L.
    - si on a un point sur la dernière ligne, succès !
    - fin boucle while
    - si la liste est vide, ça veut dire que tous les 1 contigus ont été traités. À ce moment-là, il faut reparcourir la première ligne pour en trouver un autre et recommencer.
    - si on n'a rien trouvé, échec.

    Je sais que c'est un peu dur de se convaincre que cette méthode fonctionne, mais elle est garantie par deux choses :
    - tous les 1 de L seront forcément traités, donc tous les voisins et les voisins des voisins, etc. du point de départ seront traités ;
    - le programme ne va pas boucler car les points traités sont mis à 0 dans M.

    Je reste dispo pour les questions ;)
    0
    1. Pilow Messages postés 410 Statut Membre 71
       
      Ah oui j'avais utilisé une méthode aussi a peu près similaire pour une histoire de promenade dans un labyrinthe, autant pour moi c'est beaucoup plus simple si je me souviens bien
      0
  3. Apaachee Messages postés 261 Statut Membre 47
     
    Vraiment merci pour cet algo, je regarde ça demain !
    0
  4. Apaachee Messages postés 261 Statut Membre 47
     
    les 1 de mon 1er exemple correspondent aux 'j' de ma fonction

    public int estGagnant(){
    		//Renvoit 0 si pas de gagnant, gagnant si on connecte les 2 bords
    		//		  1 si Jaune gagne
    
    		
    		int resultat = -1;
    		int j=0;
    		
    		int condition = 0;
    		
    		//Piles
    		Pile pileI = new Pile();
    		Pile pileJ = new Pile();
    		Pile sommetSave = new Pile();
    		 
    		//On scan la première ligne pour trouver les 'j', on stocke les coordonnées dans les 2 piles
    		for(int i=0;i<nbCases;i++){
    			if(this.plateau[i][j] == 'j'){
    				pileI.empiler(i);
    				pileJ.empiler(j);
    				sommetSave.empiler(i);
    			}
    		}
    		//1er scan terminé
    		
    		while(condition == 0){
    			//Case courante
    
    			int iCourant = pileI.sommet();
    			int jCourant = pileJ.sommet();
    			int test=0;
    			
    			//Si case en dessous et jaune ET derniere ligne, partie gagnée pour Jaune !
    			if((this.plateau[iCourant][jCourant+1] == 'j') && (jCourant+1 == nbCases)){
    				return 1;
    			}
    			
    			//Si une case a coté de la courante est jaune, on empile
    			if((this.plateau[iCourant+1][jCourant] == 'j')
    			&& (!dejaPresent(pileI,pileJ,iCourant+1,jCourant))){ //Case a droite de la courante
    				test++;
    				pileI.empiler(iCourant+1);
    				pileJ.empiler(jCourant);
    			}
    			if(this.plateau[iCourant][jCourant+1] == 'j'
    			&& (!dejaPresent(pileI,pileJ,iCourant,jCourant+1))){ //Case en bas de la courante
    				test++;
    				pileI.empiler(iCourant);
    				pileJ.empiler(jCourant+1);
    			}
    			if(this.plateau[iCourant-1][jCourant] == 'j'
    			&& (!dejaPresent(pileI,pileJ,iCourant-1,jCourant))){ //Case à gauche
    				test++;
    				pileI.empiler(iCourant-1);
    				pileJ.empiler(jCourant);
    			}
    			if(this.plateau[iCourant][jCourant-1] == 'j'
    			&& (!dejaPresent(pileI,pileJ,iCourant,jCourant-1))){ //Case au-dessus
    				test++;
    				pileI.empiler(iCourant);
    				pileJ.empiler(jCourant-1);
    			}
    			
    			//Si on enregistre 2 données, on sauvegarde le(s) sommet(s)
    			while(test > 1){
    				sommetSave.empiler(sommetSave.sommet()-(test+1));
    				test--;
    			}
    			
    			//Si pas de nouveau chemin
    			if(test == 0){
    				//Si en plus pas de résultat sauvegardé
    				if(sommetSave.estVide()){
    					condition = 1;
    				}
    				else{
    					pileI.setSommet(sommetSave.sommet());
    					pileJ.setSommet(sommetSave.sommet());
    					sommetSave.depiler();
    				}
    			}
    		}
    		
    		return resultat;
    	}
    	public boolean dejaPresent( Pile a, Pile b, int i, int j){
    		//Fonction qui recherche dans a et b si i et j sont déja présent
    		boolean result = false;
    		while(a.estVide()){
    			if((a.sommet() == i) && (b.sommet() == j))
    				result = true;
    			a.depiler();
    			b.depiler();
    		}
    		return result;
    	}
    


    Erreur : java.lang.ArrayIndexOutOfBoundsException : -1
    Je connais cette erreur mais je suis un peu largué pour la corriger :/
    J'ai besoin de vous ! :)
    0
    1. Pacorabanix Messages postés 4122 Date d'inscription   Statut Membre Dernière intervention   663
       
      déjà dis-nous quand elle apparait ! (met des System.out.println() dans ton code pour tracer sur la cousole)
      0
      1. Pacorabanix Messages postés 4122 Date d'inscription   Statut Membre Dernière intervention   663 > Pacorabanix Messages postés 4122 Date d'inscription   Statut Membre Dernière intervention  
         
        un rapide coup d'oeil me dis aussi qu'il est probable qu'elle soit par là :

        jCourant+1

        si jCourant est le dernier ça pose problème.
        0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. loupius Messages postés 789 Statut Membre 148
     
    Convaincu que la récursivité était la méthode la plus simple, je vous ai pondu la solution suivante:
    #include <stdio.h>
    #include <stdlib.h>
    
    #define LIGNE 8
    #define COLON 7
    
    int matrice [LIGNE][COLON] =
    { { 0, 0, 0, 0, 1, 0, 0 },
      { 0, 0, 0, 0, 1, 1, 0 },
      { 0, 0, 0, 0, 0, 1, 0 },
      { 0, 0, 0, 0, 1, 1, 0 },
      { 0, 0, 0, 0, 1, 0, 0 },
      { 0, 0, 0, 1, 1, 1, 0 },
      { 0, 0, 1, 1, 0, 1, 0 },
      { 0, 0, 0, 0, 1, 1, 0 } };
    
    int recursive (int matrice[][COLON], int colon, int nbLigne, int nbColon)
    {
      if (!matrice[0][colon])
        return 0;  // Non trouvable
      // Recherche du '1' le plus à gauche
      while ( (colon) && matrice[0][colon-1])
        colon--;
      for (; (colon<nbColon) && matrice[0][colon]; colon++)
        if( (nbLigne == 1) || recursive(&matrice[1], colon, nbLigne-1, nbColon))
          return 1;   // Trouvé
      return 0;  // Non trouvé
    }
    
    int main()
     {
       int i, retour;
       for (i=0; i<COLON; i++)
         if( (retour = recursive(matrice, i, LIGNE, COLON)) )
         {
           printf("Trouvé départ=%d arrivée=%d!\n", i+1, retour);
           return (EXIT_SUCCESS);
         }
      printf("Non trouvé !\n");
      return (EXIT_FAILURE);
    }
    Bonne réflexion.
    NB: Je suis désolé, mais ce n'est que du 'C' ;-)
    0
  7. Groarh Messages postés 706 Statut Membre 185
     
    Salut loupius, comme on se retrouve ;)

    Je suis pas sûr de comprendre ta boucle while « recherche du '1' le plus à gauche ». Il me semble qu'elle parcourt une ligne de matrice de droite à gauche, mais que se passe-t-il si la première valeur rencontrée est '0' ?

    De plus, je pense que ton programme ne gère pas les parcours « qui remontent », du style :

    { { 0, 1, 0, 0, 0, 0, 0 },
      { 0, 1, 0, 0, 0, 0, 0 },
      { 0, 1, 1, 0, 1, 1, 1 },
      { 0, 0, 1, 1, 1, 0, 1 },
      { 0, 0, 0, 0, 0, 0, 1 },
      { 0, 0, 0, 0, 1, 1, 1 },
      { 0, 0, 0, 1, 1, 0, 0 },
      { 0, 0, 0, 1, 0, 0, 0 } }


    Je suis prêt à livrer le code de mon propre algorithme, mais pas avant qu'on m'ait prié à genoux ^^ j'aime bien quand les gens cherchent un peu par eux-mêmes.
    0
    1. loupius Messages postés 789 Statut Membre 148
       
      Salut,
      Ah c'est vrai je n'ai pas du tout pensé au parcours remontant !
      La boucle 'while' parcourt la ligne à partir de 'colon' (qui est forcément un '1' (testé par if (!matrice[0][colon]))) en remontant vers 'colon = 0' (le test sur 'colon' assurant de ne pas devenir négatif).
      Bonne réflexion.
      0
  8. Apaachee Messages postés 261 Statut Membre 47
     
    		int resultat = 0;
    		int j=0;
    		
    		int condition = 0;
    		
    		//Piles
    		Pile pileI = new Pile();
    		Pile pileJ = new Pile();
    		Pile sommetSave = new Pile();
    		 
    		//On scan la première ligne pour trouver les 'j', on stocke les coordonnées dans les 2 piles
    		int var = 0;
    		for(int i=0;i<nbCases;i++){
    			if(this.plateau[i][j] == 'j'){
    				pileI.empiler(i);
    				pileJ.empiler(j);
    				sommetSave.empiler(var);
    				var++;
    			}
    		}
    		
    		int passage = 1;
    		while(condition == 0){
    			
    			System.out.println("Passage dans la boucle no :"+passage);			
    			
    			int iCourant = pileI.sommet();
    			int jCourant = pileJ.sommet();
    			int test=0;
    			
    			//Si une case a coté de la courante est jaune, on empile
    			if(iCourant<nbCases){
    				if((this.plateau[iCourant+1][jCourant] == 'j')
    				&& (!dejaPresent(pileI,pileJ,iCourant+1,jCourant))){ //Case a droite de la courante
    					System.out.println("Case a droite detect");
    					test++;
    					pileI.empiler(iCourant+1);
    					pileJ.empiler(jCourant);
    				}
    			}
    			if(jCourant<nbCases){
    				if(this.plateau[iCourant][jCourant+1] == 'j'
    				&& (!dejaPresent(pileI,pileJ,iCourant,jCourant+1))){				//Case en bas de la courante
    					//Case Gagnante
    					System.out.println("jCourant+1 : "+jCourant);
    					System.out.println("iCourant+1 : "+iCourant);
    					if(jCourant+2 == nbCases){
    						System.out.println("Jaune Gagne");
    						condition = 1;
    						resultat =  1;
    					}
    					System.out.println("Case en bas detect");
    					test++;
    					pileI.empiler(iCourant);
    					pileJ.empiler(jCourant+1);
    				}
    			}
    			if(iCourant>0){
    				if(this.plateau[iCourant-1][jCourant] == 'j'
    				&& (!dejaPresent(pileI,pileJ,iCourant-1,jCourant))){ //Case à gauche
    					System.out.println("Case a gauche detect");
    					test++;
    					pileI.empiler(iCourant-1);
    					pileJ.empiler(jCourant);
    				}
    			}
    			if(jCourant > 0){
    				if(this.plateau[iCourant][jCourant-1] == 'j'
    				&& (!dejaPresent(pileI,pileJ,iCourant,jCourant-1))){ //Case au-dessus
    					System.out.println("Case au dessus detect");
    					test++;
    					pileI.empiler(iCourant);
    					pileJ.empiler(jCourant-1);
    				}
    			}
    			
    			System.out.println("Test : "+test);
    			//Si on enregistre 2 données, on sauvegarde le(s) sommet(s)
    			while(test > 1){
    				sommetSave.empiler(sommetSave.sommet()-(test+1));
    				System.out.println("Test 6");
    				test--;
    			}
    			
    			//Si pas de nouveau chemin
    			if(test == 0){
    				//Si en plus pas de résultat sauvegardé
    				if(((sommetSave.sommet)-1) == 0){
    					System.out.println("sommetSave vide, plus rien a analyser");
    					condition = 1;
    					//pain = 31;
    				}
    				else{
    					sommetSave.depiler();
    					System.out.println("Test 8");
    					System.out.println("On setSommet a : "+sommetSave.sommet());
    					pileI.setSommet(sommetSave.sommet());
    					pileJ.setSommet(sommetSave.sommet());
    					System.out.println("la new coordonnee est : ("+pileI.sommet()+","+pileJ.sommet()+")");
    				}
    			}
    			passage++;
    		}
    		
    		return resultat;
    


    Ca a l'air de fonctionner :p
    0
  9. Apaachee Messages postés 261 Statut Membre 47
     
    Ah j'ai encore des soucis de boucles infinies ;'(
    0