Adloun

algorithmique (école d'ingénieur) · Chapitre 7 · Application directe du cours

Réseau de bus : trajet de coût minimum

Graphes sans circuit et ordonnancement de projets · niveau 2

Énoncé

On reprend le réseau de l'exercice 7.2. Une ligne directe de à n'existe que si ; elle coûte , rangé dans C[i][j] ( s'il n'y a pas de ligne) :

On note le coût minimum d'un trajet de la ville à la ville , et l'ensemble des villes qui envoient un arc sur .

  • Donner l'équation de récurrence des valeurs : base et hérédité, avec l'intervalle des valeurs de .
  • Pourquoi peut-on calculer les par croissants ?
  • Écrire int[][] calculerMA(Liste[] Gp, int[][] C) qui retourne de terme général et de terme général , la ville qui précède sur un trajet optimal (on pose ). Le paramètre Gp est le graphe symétrique.
  • Écrire void acm(int[] A, int[][] C, int j) qui affiche un trajet de coût minimum de à , sous la forme 0--(5)-->1--(20)-->4.
  • Donner , et les trajets optimaux vers et vers .

Corrigé

  • Supposons le problème résolu : un trajet optimal vers arrive sur par une dernière ligne , avec , et sa partie de à est elle-même optimale (principe d'optimalité). D'où :

Si est vide, le minimum vaut : est inaccessible.

  • Tous les prédécesseurs de ont un numéro (les lignes vont de à , la numérotation est isotone) : quand on calcule par croissants, toutes les valeurs utiles sont connues.
  • On parcourt les prédécesseurs dans le graphe symétrique et l'on mémorise l'argument du minimum.

static final int INFINI = Integer.MAX_VALUE / 2;

static int[][] calculerMA(Liste[] Gp, int[][] C) { int n = Gp.length;
    int[] M = new int[n], A = new int[n];
    M[0] = 0; A[0] = -1;                              // base
    for (int j = 1; j < n; j++) {                     // par j croissants
        M[j] = INFINI; A[j] = -1;
        for (Liste l = Gp[j]; !vide(l); l = reste(l)) { int i = premier(l);
            if (M[i] + C[i][j] < M[j]) {              // meilleur trajet arrivant par i
                M[j] = M[i] + C[i][j]; A[j] = i;
            }
        }
    }                                                 // M[j] = m(j), A[j] = a(j)
    return new int[][] {M, A};
}

La valeur est Integer.MAX_VALUE / 2, pour que ne dépasse pas la capacité des int. Chaque sommet et chaque arc est touché une fois : .

  • On affiche d'abord le trajet jusqu'à , puis la dernière ligne :

static void acm(int[] A, int[][] C, int j) {
    if (j == 0) { System.out.print("0"); return; }   // trajet réduit à 0 : affiché
    acm(A, C, A[j]);                                 // trajet de 0 à a(j) affiché
    System.out.printf("--(%d)-->%d", C[A[j]][j], j); // puis la ligne a(j) --> j
}
  • Exécution :

M = [0, 5, 10, 20, 25], A = [-1, 0, 1, 2, 1]
0--(5)-->1--(20)-->4
0--(5)-->1--(5)-->2--(10)-->3

nom : M
valeurs : 0 5 10 20 25
vert : 0 1 4
fleches : 0->1 1->2 2->3 1->4
legende : flèches de a(j) vers j ; en vert : le trajet 0, 1, 4 (coût 25)

Vers , le trajet direct () est battu par () ; vers , la ligne directe () est à égalité avec : l'inégalité stricte garde le premier prédécesseur examiné.

100 % gratuit

La suite du chapitre est sur Adloun

Exercice suivant et tuteur

Sans compte : le cours, le premier QCM et 2 minutes de podcast et de vidéo. Exercices et tuteur : inscription gratuite en 30 secondes, sans carte bancaire.

Le cours du chapitre · Tous les exercices du chapitre

Exercice suivant et tuteur →