Adloun

Le sens d'une boucle décide du problème résolu

Exercice · niveau 2 · informatique (MP2I/MPI), chapitre 17 — Programmation dynamique

Énoncé

On veut économiser la mémoire du sac à dos en n'utilisant qu'une seule ligne. Ces deux fragments diffèrent d'un seul caractère. Que calcule chacun ?


/* (A) */  for (int i = 0; i < n; i++)
               for (int c = C; c >= p[i]; c--)
                   if (v[i] + m[c - p[i]] > m[c]) { m[c] = v[i] + m[c - p[i]]; }

/* (B) */  for (int i = 0; i < n; i++)
               for (int c = p[i]; c <= C; c++)
                   if (v[i] + m[c - p[i]] > m[c]) { m[c] = v[i] + m[c - p[i]]; }

Corrigé

(A) résout le sac à dos du chapitre (chaque objet au plus une fois). (B) résout le sac à dos illimité, où chaque objet peut être pris autant de fois qu'on veut. Et rien, dans le code, ne le dit.

Pourquoi. La ligne tient à la fois l'ancienne ligne et la nouvelle . Quand on lit m[c - p[i]] :

Mesure, avec deux objets , :


C=4   (A) decroissant = 4    (B) croissant = 6
C=5   (A) decroissant = 7    (B) croissant = 7
C=6   (A) decroissant = 7    (B) croissant = 9
C=7   (A) decroissant = 7    (B) croissant = 10

À , (A) rend (les deux objets, poids ) et (B) rend (trois fois l'objet de poids ). À les deux coïncident, ce qui est le pire cas pour le testeur : un jeu de tests limité à n'aurait rien vu. Le chapitre chap:discipline le dit autrement : on teste aux frontières, et ici la frontière est la capacité où reprendre un objet devient possible.

À retenir. Une réduction de mémoire n'est jamais neutre. Ici elle ne change pas la complexité en temps, mais elle rend le sens de la boucle sémantique : la même ligne de code résout deux problèmes différents selon un signe. Quand on écrase la table, on écrit l'ordre de parcours dans un commentaire, au-dessus de la boucle.

Les autres exercices de ce chapitre Le cours du chapitre

Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.