Graphes et algorithmes - TP 3 - corrigé

Michel Couprie, Gilles Bertrand


0. Les données


1. Dijkstra dans le métro

#define INFINITY LONG_MAX
/* ====================================================================== */
/*! \fn void Dijkstra(graphe * g, int i)
    \param g (entrée) : un graphe pondéré. La pondération de chaque arc doit 
                        se trouver dans le champ \b v_arc de la structure \b cell .
    \param i (entrée) : un sommet de \b g.
    \brief calcule, pour chaque sommet x de g, la longueur d'un plus court
           chemin de i vers x. Cette longueur est stockée dans le champ
           \b v_sommets de \b g .
*/
void Dijkstra(graphe * g, int i)
/* ====================================================================== */
{
  int n = g->nsom;
  boolean * S = EnsembleVide(n);
  int k, x, y;
  pcell p;
  TYP_VSOM vmin;

  S[i] = TRUE;
  for (k = 0; k < n; k++) g->v_sommets[k] = INFINITY;
  g->v_sommets[i] = 0;
  k = 1;
  x = i;
  while ((k < n) && (g->v_sommets[x] < INFINITY))
  {
    for (p = g->gamma[x]; p != NULL; p = p->next)
    { /* pour tout y successeur de x */
      y = p->som;
      if (!S[y])
      {
        g->v_sommets[y] = min((g->v_sommets[y]),(g->v_sommets[x]+p->v_arc));
      } // if (!S[y])
    } // for p
    // extraire un sommet x hors de S de valeur g->v_sommets minimale
    vmin = INFINITY;
    for (y = 0; y < n; y++)
      if (!S[y]) 
        if (g->v_sommets[y] <= vmin) { x = y; vmin = g->v_sommets[y]; }
    k++; 
    S[x] = TRUE;
  } // while ((k < n) && (g->v_sommets[x] < INFINITY))

} /* Dijkstra() */
Note : on peut ajouter un paramètre à cette procédure pour arrêter le travail dès qu'un sommet donné est atteint. Cela rendra plus efficace la recherche d'un plus court chemin d'un sommet d vers un sommet a.


2. Plus court chemin

/* ====================================================================== */
/*! \fn graphe * PCC(graphe * g, int i, int a)
    \param g (entrée) : un graphe pondéré. La pondération de chaque arc doit 
                        se trouver dans le champ \b v_arc de la structure \b cell .
    \param i (entrée) : un sommet de \b g.
    \param a (entrée) : un sommet de \b g.
    \return un plus court chemin de d vers a sous forme d'un graphe. 
    \brief trouve un plus court chemin de d vers a, et retourne ce chemin sous forme d'un graphe. 
*/
graphe *PCC(graphe * g, int i, int a)
/* ====================================================================== */
{
  int n = g->nsom;
  boolean * S = EnsembleVide(n);
  int k, s, t;
  pcell p;
  TYP_VARC vmin, v;
  graphe * pcc = InitGraphe(n, n-1); /* pour le resultat */
  graphe * g_1 = Symetrique(g);
  int n_som_explore = 0;

  // DIJKSTRA (avec arret des que le sommet a est atteint)

  S[i] = TRUE;
  for (k = 0; k < n; k++) g->v_sommets[k] = INFINITY;
  g->v_sommets[i] = 0;
  s = i;
  while ((s != a) && (g->v_sommets[s] < INFINITY))
  {
    n_som_explore++;
    pcc->v_sommets[s] = 1; // pour le coloriage des sommets explores
    for (p = g->gamma[s]; p != NULL; p = p->next)
    { /* pour tout t successeur de s */
      t = p->som;
      if (!S[t])
      {
        v = g->v_sommets[s]+p->v_arc;
        if (g->v_sommets[t] > v) g->v_sommets[t] = v;
      } // if (!S[t])
    } // for p
    // extraire un sommet s hors de S de valeur g->v_sommets minimale
    vmin = INFINITY;
    for (t = 0; t < n; t++)
      if (!S[t]) 
        if (g->v_sommets[t] <= vmin) { s = t; vmin = g->v_sommets[t]; }
    S[s] = TRUE;
  } // while ((s != a) && (g->v_sommets[s] < INFINITY))
  if (s != a)
  {
    printf("WARNING: pas de pcc trouve (s = %d , a = %d)\n", s, a);
    return NULL;    
  }
  printf("pi(a) = %d\n", g->v_sommets[a]);
  printf("nb. sommets explores = %d\n", n_som_explore);

  // CONSTRUCTION DU PCC

  while (s != i)
  {
    for (p = g_1->gamma[s]; p != NULL; p = p->next)
    { /* pour tout t predecesseur de s */
      t = p->som;
      if ((g->v_sommets[s]-g->v_sommets[t]) == p->v_arc) 
      {
        AjouteArcValue(pcc, t, s, p->v_arc);
        s = t;
        break;
      }
    } // for p
  }

  TermineGraphe(g_1);
  for (k = 0; k < n; k++) { pcc->x[k] = g->x[k]; pcc->y[k] = g->y[k]; }
  return pcc;

} /* PCC() */

Programme principal avec visualisation :

/* ====================================================================== */
void main(int argc, char **argv)
/* ====================================================================== */
{
  graphe *g, *pcc;
  int na, ns;     /* nombre d'arcs, nombre de sommets */
  int d, a;

  if (argc != 4)
  {
    fprintf(stderr, "usage: %s graphe_value d a\n", argv[0]);
    exit(0);
  }

  g = ReadGraphe(argv[1]);             /* lit le graphe a partir du fichier */
  d = atoi(argv[2]);
  a = atoi(argv[3]);
  pcc = PCC(g, d, a);
  
  // genere une figure en PostScript
  EPSGraphe(pcc, "pcc.ps", 4, 2, 25, 0, 0, 1, 0);

  TermineGraphe(g);
  TermineGraphe(pcc);

} /* main() */


3. Variante Le plus simple est de modifier l'algorithme, mais attention, la stratégie ci-dessus pour construire le PCC ne marchera plus. Il faudra au cours de l'execution de Dijkstra mémoriser des pointeurs inverses (graphe auxiliaire).


4. Approche A*

#define INFINITY LONG_MAX
#define ECHELLE 25.7
#define VITESSE 10.0
/* ====================================================================== */
/*! \fn graphe * PCCheuristique(graphe * g, int d, int a)
    \param g (entrée) : un graphe pondéré. La pondération de chaque arc doit 
                        se trouver dans le champ \b v_arc de la structure \b cell .
                        les coordonnées cartesiennes de chaque sommet doivent se trouver
                        dans les champs \b x et \b y de \b g.
    \param d (entrée) : un sommet de \b g.
    \param a (entrée) : un sommet de \b g.
    \return un plus court chemin de d vers a sous forme d'un graphe. 
    \brief trouve un plus court chemin de d vers a, et retourne ce chemin sous forme d'un graphe. 
*/
graphe * PCCheuristique(graphe * g, int d, int a)
/* ====================================================================== */
{
  int n = g->nsom;
  boolean * S = EnsembleVide(n);
  int k, s, t, x;
  pcell p;
  TYP_VARC vmin, v, h;
  graphe * pcc = InitGraphe(n, n-1); /* pour le resultat */
  graphe * g_1 = Symetrique(g);
  int n_som_explore = 0;

  // DIJKSTRA AVEC HEURISTIQUE

  S[d] = TRUE;
  for (k = 0; k < n; k++) g->v_sommets[k] = INFINITY;
  g->v_sommets[d] = 0;
  k = 1;
  s = d;
  while ((s != a) && (g->v_sommets[s] < INFINITY))
  {
    n_som_explore++;
    pcc->v_sommets[s] = 1; // pour le coloriage des sommets explores
    for (p = g->gamma[s]; p != NULL; p = p->next)
    { /* pour tout t successeur de s */
      t = p->som;
      if (!S[t])
      {
        v = g->v_sommets[s]+p->v_arc;
        if (g->v_sommets[t] > v) g->v_sommets[t] = v;
      } // if (!S[t])
    } // for p
    // extraire un sommet s hors de S de valeur g->v_sommets[s] + h(s)  minimale,
    // avec h(s) = dist(s,a)*ECHELLE/VITESSE
    vmin = INFINITY;
    for (t = 0; t < n; t++)
      if (!S[t])
      { 
        h = (TYP_VARC)(dist(g->x[t],g->y[t],g->x[a],g->y[a]) * ECHELLE / VITESSE);
        v = g->v_sommets[t];
        if (v < INFINITY) v += h;
        if (v <= vmin) { s = t; vmin = v; }
      }
    k++; 
    S[s] = TRUE;
  } // while ((s != a) && (g->v_sommets[s] < INFINITY))
  if (s != a)
  {
    printf("WARNING: pas de pcc trouve \n");
    return pcc;    
  }
  printf("pi(a) = %d\n", g->v_sommets[a]);
  printf("nb. sommets explores = %d\n", n_som_explore);

  // CONSTRUCTION DU PCC

  while (s != d)
  {
    for (p = g_1->gamma[s]; p != NULL; p = p->next)
    { /* pour tout t predecesseur de s */
      t = p->som;
      if ((g->v_sommets[s]-g->v_sommets[t]) == p->v_arc) 
      {
        AjouteArcValue(pcc, t, s, p->v_arc);
        s = t;
        break;
      }
    } // for p
    if (p == NULL)
    {
      printf("WARNING: pas de pcc trouve \n");
      TermineGraphe(g_1);
      return pcc;
    }
  }
  TermineGraphe(g_1);
  for (k = 0; k < n; k++) { pcc->x[k] = g->x[k]; pcc->y[k] = g->y[k]; }
  return pcc;

} /* PCCheuristique() */

Programme principal avec visualisation :

/* ====================================================================== */
void main(int argc, char **argv)
/* ====================================================================== */
{
  graphe *g, *pcc;
  int na, ns;     /* nombre d'arcs, nombre de sommets */
  int d, a;

  if (argc != 4)
  {
    fprintf(stderr, "usage: %s graphe_value d a\n", argv[0]);
    exit(0);
  }

  g = ReadGraphe(argv[1]);             /* lit le graphe a partir du fichier */
  d = atoi(argv[2]);
  a = atoi(argv[3]);
  pcc = PCCheuristique(g, d, a);
  
  // genere une figure en PostScript
  EPSGraphe(pcc, "pcc.ps", 4, 2, 25, 0, 0, 1, 0);

  TermineGraphe(g);
  TermineGraphe(pcc);

} /* main() */


Dernière mise à jour :  par Michel Couprie.