Mon algorithme ne fonctionne pas

Fermé
hunter_civ Messages postés 9 Date d'inscription jeudi 8 octobre 2020 Statut Membre Dernière intervention 27 octobre 2020 - Modifié le 27 oct. 2020 à 22:52
mamiemando Messages postés 33284 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 25 septembre 2024 - 30 nov. 2020 à 15:58
Bonjour,

J'ai élaboré un algorithme pour résoudre le problème suivant:


Nous sommes en l'an 3000 et tout l'univers est infecté par un virus inconnu. Le virus est si dangereux que la pandémie d'il y a 1000 ans, qui s'est répandue dans tout le monde civilisé, ressemble à un rhume en comparaison. Ce virus détruit non seulement n'importe quel être vivant, mais aussi des planètes entières, comme le montre l'image que nous avons obtenue du télescope Hubble.
Même si les meilleurs cerveaux de cette génération se sont tous réunis à l'université de la planète Ankh-Morpork, le développement du vaccin est essentiellement au point 0. Les scientifiques ont besoin d'un échantillon de ce virus pour avoir de bonnes chances de développer un vaccin. La bonne nouvelle est que l'équipage du vaisseau spatial Planet Express a obtenu un échantillon d'ARN.
La bataille n'est pas encore gagnée! Le virus se propage et nous avons besoin que l'échantillon soit livré de l'emplacement actuel du navire à l'université. C'est pourquoi ils ont décidé de voyager léger et rapide. Pourtant, ils doivent faire le plein sur chaque planète qu'ils visitent
Nous devons maintenant créer un plan de trajectoire pour le navire. L'équipage a une carte de l'univers connu où toutes les planètes infectées sont marquées. Chaque planète est également connectée à quelques autres planètes entre lesquelles elles sont capables de voyager sur un réservoir plein. Ils peuvent également voyager vers des planètes infectées, mais ils sont infectés, ce qui est acceptable pour eux. L’équipage infecté ne peut survivre qu’à quelques sauts, mais s’il parvient à se rendre à l’université à temps, les scientifiques croient pouvoir sauver la vie de l’équipage.
Non seulement la race humaine crée un vaccin. Il y a des extraterrestres qui prétendent l'avoir. Comme leurs planètes n'étaient pas encore infectées, leur vaccin peut fonctionner. L'équipage peut payer ces mondes pour visiter et soigner leur infection.
Votre tâche est de décider s'il existe un chemin entre l'emplacement actuel des navires et l'université. Si l'équipage survit et arrive sur la planète, vous devez imprimer les planètes dans l'ordre où elles les ont visitées. S'il n'y a aucun moyen possible d'arriver à l'université en vie, alors… vous devriez chérir le temps qui vous reste avec vos proches.

L'input est imposé de cette manière :
•Sur la première ligne, il y a deux entiers N et M spécifiant respectivement le nombre de planètes dans l'univers connu et le nombre de trajets spatiaux connus. La numérotation des planètes est en base zéro, leurs identifiants sont donc 0,…, N-1.
•Sur la deuxième ligne, il y a trois nombres s, t et l. Le premier chiffre représente la planète initiale, le deuxième représente la planète terminale et le troisième est un nombre d'arrêts de vaisseau spatial qu'un équipage dure lorsqu'il est infecté.
•Sur la troisième ligne, il y a un nombre K spécifiant le nombre de planètes réellement infectées. Si K> 0, alors cette ligne est suivie de K identificateurs de planètes réellement infectées.
•Sur la ligne suivante, il y a un nombre D spécifiant le nombre de planètes où un vaccin expérimental peut être acheté. De D> 0, alors cette ligne est suivie par les identificateurs D de telles planètes.
•Ensuite, M lignes se composent chacune de deux entiers x y, 0 ≤ x, y <N, qui identifie deux planètes qui sont mutuellement réalisables sur un seul réservoir.
•L'entrée est toujours valide.
•La planète initiale et la planète terminale ne sont ni infectées, ni un vaccin ne peut être acheté sur elles.
•Selon la définition du problème, il n'y a pas de planète v telle que v soit infectée et un vaccin expérimental peut y être acheté en même temps.


OUTPUT
• La sortie se compose d'une seule ligne. S'il y a une marche possible entre la planète s et la planète t, vous devez sortir cette marche. Sinon, sortie numéro -1.
• Une promenade entre s et t n'est généralement pas exclusive. Vous pouvez en générer un arbitraire.
• Les marches plus longues que les planètes max (3D * N, N) seront refusées.

exemple:
intput
7 6
0 5 2
1
2
1
6
1 0
4 3
4 5
6 3
2 3
2 1

output
0 1 3 4

Voici l'algorithme que j'ai élaboré (les variables sont en anglais car je suis des cours à l'étranger).
Je le teste avec 3 planètes sans remèdes et virus mais il me retourne -1. J'ai placé quelques print pour voir le chemin parcouru et je me rends compte que dès qu'il atteint la bonne planète il ne s'arrête pas et je ne voit pas pourquoi.

#include <stdio.h>
#define max(a,b) (a>=b?a:b)


int N; //nombre de planète (noeuds)
int M; //nombre de trajets (arretes)
int s; //planète initial
int t; //planète final
int l; //nombre d'arrets apres infection
int K; //nombre de planète infectée
int D; //NOMBRE DE PLANETE VACCIN
int compteurPlanete=0;
int z; //variable pour for infecte et vaccin
int top =-1; //variable de la pile chemin*/
int start, end; // origine et pointe des arretes
int adjMatrix[20000][20000];
int infectes[200000];
int chemin[200000];
int vaccins[30];

int Travel(int x, int survivalTime, int nbMax){
  if (x == t ){ //position atteint
    return 0;
  }
  if (infectes[x]==1 && survivalTime == -1) { //planète infectée et état sain
  survivalTime=l;
  }

  if (vaccins[x]==1) {  // La planète a un vaccin
  survivalTime=-1;
 }

  if (survivalTime==0 || nbMax==0) {
     return 1;  // echec
  }


  for (int i=0;i<N;i++) {  //For every position i adjacent to x:
    if (adjMatrix[x][i] !=0) {
    if (survivalTime==-1) {
     Travel(i, survivalTime, nbMax-1); //mark x with green color
     chemin[++top] = i;
     compteurPlanete++;

      }
    else {
     Travel(i, survivalTime-1, nbMax-1);    //mark x with green color
     chemin[++top] = i;
     compteurPlanete++;

    }
    }
  }
}

void addEdge(int start,int end) {
   adjMatrix[start][end] = 1;
   adjMatrix[end][start] = 1;
}

int main (){

  scanf( "%d %d", &N, &M );
  scanf( "%d %d %d", &s, &t, &l);
  scanf("%d", &K);


  if (K>0) {                      // I tableau des planetes infectes
   for (int k=0; k<K;k++)
     scanf("%d", &z);
    infectes[z-1]=1;
 }

  scanf("%d", &D);
  //tableau avec ttes les planètes avec vaccins
  if (D>0) {                      // vaccin tableau des planetes avec vaccins
   for (int d=0; d<D;d++ )
     scanf("%d", &z);
    vaccins[z-1]=1;
   }

  for(int i = 0; i < N; i++){ // set adjacency
    vaccins[i]=0;
    infectes[i]=0;
    for(int j = 0; j < N; j++){ // matrix to 0
      adjMatrix[i][j] = 0;    //initialise la matrice à 0
    }
  }

  int nbMax= max(3*D * N, N); // nombre de trajets maximal possible
  //tableau avec ttes les bonnes planètes

  for(int e = 0; e< M; e++){
    scanf ("%d %d", &start, &end);
    addEdge(start, end);
  }

 int result= Travel (s,-1,nbMax);
 if (result==1) {
        printf("-1");  //ECHEC
 }
 else{
        for (int c=compteurPlanete-1;c>=0;c--) { //SUCCES
            printf("%d ",chemin[c]);

   }
 }

}


Merci d'avance pour ceux qui se plongeront dans le sujet.
Configuration: Windows / Chrome 86.0.4240.111
A voir également:

1 réponse

mamiemando Messages postés 33284 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 25 septembre 2024 7 787
30 nov. 2020 à 15:58
Bonjour,

Même si le français n'est pas parfait, le sujet de l'exercice est super, ça change des exercices bien scolaires :-)))))

Peux-tu indiquer quel fichier d'entrée tu as utilisé ?

Ensuite la manière dont est formulé ton problème incite à partir sur un Branch and Bound. C'est l'approche que tu as suivi. Le code semble correct à première vue, hormis que tu n'arrêtes pas ton B&B quand une solution est trouvée. Une manière de faire pourrait consister à passer en paramètre de ta fonction
Travel
un booléen (partagé) par tous les appels récursifs, qui quand il est vrai, quitte la fonction
Travel
. En effet l'instruction
return
ne fait que quitter l'appel en cours (donc le nœud courant de ton Branch & Bound) pas les éventuelles autres branches en cours d'exploration.

#include <stdbool.h>

void Travel( ..., bool * found) {
if (x == t) {
found = true;
}
if (found) return;
...
}

int main(){
...
bool found = false;
Travel(..., &found)
...
if (found) {
// Afficher la solution trouvée
}
}


Optimisations

Dans le cas particulier où il n'y a pas de planète infectée, tu peux aussi directement utiliser un algorithme de Dijkstra qui sera bien plus efficace. Ainsi, il ne serait pas déraisonnable de chercher au préalable un chemin dans le sous-graphe en ignorant les sommets associés aux planètes infectées.

Si tu n'en trouves pas, tu peux répéter cette recherche en t'assurant qu'il n'y a pas de planète infectée dans le chemin trouvée
l
bonds avant l'arrivée.

Ensuite il serait intéressant de voir dans quelle mesure un algorithme de Dijkstra généralisé (où la métrique d'un chemin est le couple qui contient la distance parcourue et la durée de vie de l'équipage), dont l'opération de comparaison est l'ordre lexicographique (distance parcourue, - durée de vie de l'équipage) et dont l'opération de concaténation est l'addition pour la distance parcourue et la mise à jour calcule un résultat correct. En toute rigueur il faudrait alors contrôler que la structure algébrique ainsi engendrée est un semi-anneau. Pour plus de détails, voir ce livre.

Bonne chance
0