Programmation dynamique itérative☘
Modélisation☘
Dans la partie précédente, nous avons associé un pixel de l'image à une valeur entière :
- 0 si ce pixel est noir,
- 1 s'il est le coin bas-droite d'un carré blanc de côté 1 ;
- 2 s'il est le coin bas-droite d'un carré blanc de côté 2 ;
- etc...
Ainsi, l'image ci-dessous à gauche peut être modélisée par le tableau ci-dessous à droite :
En Python, le tableau de droite va être modélisé sous la forme d'un tableau de
tableau (une matrice) nommée memo
(par exemple) et sera défini ainsi :
1 2 3 4 5 6 |
|
- Dans l'image de gauche, les coordonnées du pixel noir sont
(3, 2)
: on donne d'abord l'abscisse, puis l'ordonnée. - Dans le tableau de droite, qui modélise l'image, la valeur « 0 »
représente le pixel noir. « 0 » est donc la valeur de l'élément
memo[2][3]
: on écrit d'abord le numéro de ligne, puis le numéro de colonne.
A retenir
Le pixel (x, y)
de l'image sera associé à un entier placé dans la case memo[y][x]
du tableau.
Rappel☘
On désigne par memo
le tableau qui, à une image carrée composée de pixels
noirs et blancs, associe pour chaque pixel (x, y)
une valeur entière selon
la relation de récurrence suivante :
Relation de récurrence
- Si le pixel
(x, y)
est noir, alors
memo[y][x] = 0
. - Si
(x, y)
est blanc et qu'il appartient à la première ligne (en haut) ou la première colonne (à gauche), alors
memo[y][x] = 1
. - Si
(x, y)
est blanc et qu'il n'est pas dans le cas précédent, alors
memo[y][x] = 1 + min(memo[y][x-1], memo[y-1][x-1], memo[y-1][x])
.
Question n°1☘
A l'aide de la relation de récurrence précédente, complétez le code de la
fonction pgcb_iter()
spécifiée ci-dessous afin qu'elle renvoie le tableau
memo
associé à l'image source
.
1 2 3 4 5 6 7 |
|
Un premier exemple pour tester
Effectuez un clic droit sur l'image ci-contre afin de l'enregistrer . Voici une version agrandie de cette image :
Vérifiez que le tableau renvoyé pour cette image est :
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1]
[1, 2, 2, 2, 2, 0, 1, 2, 0, 1, 2, 2, 2, 2, 1, 1, 2, 2, 2, 2]
[1, 2, 3, 0, 0, 1, 1, 2, 1, 1, 2, 3, 3, 0, 1, 2, 2, 3, 3, 3]
[0, 1, 0, 1, 0, 0, 1, 2, 2, 2, 2, 3, 0, 1, 1, 2, 3, 3, 4, 4]
[0, 1, 1, 1, 1, 0, 1, 2, 3, 3, 3, 0, 1, 1, 2, 2, 3, 4, 4, 5]
[1, 1, 2, 2, 0, 1, 1, 2, 3, 4, 4, 1, 1, 2, 2, 3, 3, 4, 5, 5]
[1, 2, 2, 3, 1, 1, 2, 2, 3, 4, 0, 1, 2, 2, 3, 3, 4, 4, 5, 6]
[1, 2, 0, 1, 2, 0, 1, 0, 1, 2, 1, 1, 2, 3, 3, 4, 4, 5, 0, 1]
[1, 0, 1, 0, 1, 1, 1, 0, 1, 2, 2, 2, 2, 3, 4, 4, 5, 5, 1, 1]
[1, 0, 1, 1, 1, 2, 2, 1, 1, 2, 3, 3, 3, 3, 0, 1, 2, 3, 0, 1]
[1, 1, 1, 2, 0, 1, 2, 2, 2, 2, 3, 4, 4, 0, 1, 1, 2, 3, 1, 1]
[1, 2, 2, 2, 1, 1, 2, 3, 3, 3, 3, 4, 5, 0, 1, 2, 2, 3, 2, 0]
[1, 2, 3, 3, 2, 2, 0, 1, 2, 3, 4, 4, 5, 1, 1, 2, 3, 3, 3, 1]
[1, 2, 3, 4, 3, 3, 1, 1, 2, 3, 4, 5, 5, 2, 2, 2, 3, 0, 1, 2]
[1, 2, 0, 1, 2, 3, 2, 2, 2, 3, 4, 5, 6, 0, 1, 2, 3, 1, 1, 2]
[1, 2, 1, 1, 2, 3, 3, 0, 1, 2, 0, 1, 2, 1, 1, 2, 3, 2, 2, 2]
[1, 2, 2, 2, 2, 3, 4, 1, 1, 2, 1, 1, 2, 0, 1, 2, 3, 0, 0, 1]
[1, 2, 3, 3, 3, 3, 4, 0, 1, 2, 2, 0, 1, 1, 1, 2, 3, 1, 1, 1]
[1, 0, 1, 2, 3, 4, 0, 1, 1, 2, 3, 1, 1, 2, 2, 2, 3, 2, 2, 0]
[0, 1, 1, 2, 0, 1, 1, 0, 1, 2, 3, 2, 2, 2, 0, 1, 2, 3, 3, 1]
Un second exemple pour tester
Effectuez un clic droit sur l'image ci-contre afin de l'enregistrer . Voici une version agrandie de cette image :
Vérifiez que le tableau renvoyé pour cette image est :
[1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1]
[1, 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 0, 1, 2, 2, 0, 0, 0, 0, 1, 2, 2, 2, 2, 0, 1, 1, 1, 2]
[1, 2, 3, 3, 3, 3, 3, 0, 1, 2, 3, 3, 1, 1, 2, 3, 1, 1, 1, 1, 0, 1, 2, 3, 3, 1, 1, 0, 1, 2]
[1, 2, 3, 4, 4, 4, 4, 1, 1, 2, 3, 4, 2, 2, 2, 3, 2, 2, 2, 0, 0, 1, 2, 3, 4, 2, 2, 0, 1, 2]
[1, 2, 3, 4, 5, 5, 5, 2, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 0, 1, 0, 0, 1, 2, 0, 1, 1, 1, 0]
[1, 2, 3, 4, 5, 6, 6, 3, 1, 1, 2, 3, 4, 4, 0, 1, 2, 3, 4, 1, 1, 1, 1, 0, 1, 1, 1, 2, 2, 1]
[1, 2, 3, 4, 5, 6, 7, 4, 2, 2, 2, 3, 4, 5, 1, 0, 1, 2, 3, 2, 2, 2, 0, 1, 1, 2, 2, 2, 3, 0]
[0, 1, 2, 3, 4, 5, 6, 5, 3, 3, 3, 3, 4, 5, 2, 1, 1, 2, 3, 3, 3, 3, 1, 1, 2, 2, 3, 0, 1, 1]
[1, 1, 2, 3, 4, 5, 6, 6, 4, 4, 4, 4, 4, 5, 3, 2, 0, 0, 1, 2, 0, 1, 0, 1, 2, 3, 0, 1, 1, 0]
[1, 2, 2, 3, 4, 5, 6, 7, 5, 0, 0, 1, 2, 3, 4, 3, 0, 1, 1, 2, 1, 0, 1, 1, 2, 3, 1, 1, 2, 1]
[1, 2, 3, 3, 0, 1, 0, 1, 0, 1, 1, 1, 2, 3, 4, 4, 1, 1, 2, 2, 0, 1, 1, 2, 2, 0, 1, 2, 0, 1]
[1, 2, 3, 4, 1, 1, 0, 1, 1, 1, 2, 2, 2, 0, 1, 2, 2, 2, 2, 3, 0, 1, 2, 2, 3, 1, 1, 2, 1, 1]
[1, 2, 3, 4, 2, 2, 1, 1, 2, 2, 2, 0, 1, 1, 0, 1, 2, 3, 3, 3, 1, 0, 1, 0, 1, 2, 2, 2, 2, 2]
[1, 2, 3, 0, 1, 2, 2, 2, 0, 0, 1, 1, 1, 2, 1, 1, 2, 3, 0, 1, 0, 1, 1, 0, 1, 2, 3, 3, 3, 3]
[1, 2, 0, 1, 1, 2, 3, 3, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 1, 1, 1, 1, 0, 1, 1, 2, 3, 4, 4, 4]
[1, 2, 1, 0, 1, 2, 3, 4, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 2, 2, 3, 4, 0, 1]
[1, 2, 2, 1, 1, 2, 3, 4, 3, 3, 3, 3, 3, 4, 0, 1, 2, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3, 4, 1, 1]
[1, 2, 3, 2, 2, 2, 3, 4, 4, 4, 4, 0, 1, 2, 0, 1, 2, 0, 1, 2, 3, 4, 0, 1, 0, 1, 2, 0, 1, 2]
[1, 2, 3, 3, 3, 0, 1, 2, 3, 4, 5, 1, 0, 0, 1, 1, 2, 1, 1, 2, 3, 4, 1, 1, 1, 0, 1, 1, 1, 2]
[0, 1, 2, 3, 0, 1, 1, 2, 3, 4, 0, 1, 1, 1, 1, 2, 2, 0, 1, 2, 3, 4, 2, 2, 2, 1, 1, 2, 2, 2]
[1, 1, 2, 3, 1, 1, 2, 2, 3, 4, 1, 1, 2, 2, 2, 2, 3, 1, 1, 2, 0, 1, 2, 3, 3, 2, 2, 2, 3, 3]
[1, 2, 2, 3, 2, 2, 2, 0, 1, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 0, 1, 2, 3, 4, 3, 3, 3, 3, 4]
[1, 2, 3, 3, 3, 3, 3, 1, 0, 1, 2, 3, 3, 3, 4, 4, 4, 0, 1, 2, 1, 1, 0, 1, 2, 3, 4, 4, 4, 4]
[1, 2, 3, 4, 4, 4, 4, 0, 1, 1, 2, 3, 4, 4, 4, 5, 5, 1, 1, 2, 2, 2, 1, 1, 2, 3, 4, 5, 5, 5]
[1, 2, 3, 4, 5, 5, 5, 1, 1, 0, 1, 2, 3, 4, 5, 5, 6, 2, 2, 2, 3, 3, 2, 2, 2, 3, 4, 5, 6, 6]
[1, 0, 1, 2, 0, 0, 1, 2, 2, 0, 1, 2, 3, 4, 5, 6, 6, 3, 3, 0, 1, 2, 0, 1, 2, 3, 4, 5, 6, 7]
[1, 1, 0, 1, 1, 1, 0, 1, 2, 1, 1, 2, 3, 4, 5, 6, 7, 4, 4, 1, 1, 2, 1, 1, 0, 1, 2, 3, 4, 5]
[1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 0, 1, 2, 3, 4, 5, 6, 5, 5, 2, 2, 2, 0, 1, 1, 1, 2, 3, 4, 5]
[1, 2, 2, 2, 2, 3, 2, 2, 2, 0, 1, 1, 2, 3, 4, 5, 6, 6, 6, 3, 0, 1, 1, 1, 2, 2, 0, 0, 1, 2]
[1, 2, 3, 3, 3, 3, 3, 3, 3, 1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 4, 1, 1, 2, 2, 2, 3, 0, 1, 1, 2]
Une piste
On peut commencer par initialiser un tableau de n
lignes et n
colonnes, où n
est le nombre de pixels d'un des côtés de l'image carrée
Une solution
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Question n°2☘
Une lecture du tableau memo
permet de rapidement identifier la taille des plus grands carrés blancs et leur position. Ainsi :
-
pour cette première image (à gauche), on peut identifier les carrés mis en valeur à droite :
-
pour cette seconde image (à gauche), on peut identifier les carrés mis en valeur à droite :
En utilisant la fonction pgcb_iter()
programmée dans la question précédente,
complétez le code de la fonction recherche_pgcb
qui renvoie la taille
(en pixels) d'un côté du plus grand carré blanc de l'image, ainsi que la
listes des pixels haut-gauche de ce (ou ces) carré(s).
1 2 3 4 5 6 7 |
|
Un premier exemple pour tester
Avec l'image ci-contre dont la version agrandie est :
on obtient le tuple :
(6, [(14, 1), (7, 9)])
Un second exemple pour tester
Avec l'image ci-contre dont la version agrandie est :
on obtient le tuple :
(7, [(0, 0), (1, 3), (23, 19), (10, 20), (12, 23)])
Une piste
On peut commencer par rechercher la liste des coordonnées des pixels bas/droite.
- Pour l'exemple n°1, cette liste est :
[(19, 6), (12, 14)]
. - Pour l'exemple n°2, cette liste est :
[(6, 6), (7, 9), (29, 35), (16, 26), (18, 29)]
.
Une solution
On a le tableau des coordonnées des pixels bas-droite ainsi que la dimension des côtés des plus grands carrés blancs. On peut donc en déduire les coordonnées des pixels haut-gauche de ces carrés...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Question n°3☘
En utilisant le module time
, comparez le temps de calcul de la fonction
recherche_pgcb_iter()
avec celui des fonctions recherche_pgcb_for()
,
recherche_pgcb_while()
et recherche_pgcb_glouton()
pour chacune des
images ci-dessous :
Image n°1 | Image n°2 | Image n°3 |
---|---|---|
Programmes à comparer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
|
Une solution
Voici un exemple de résultats. On peut à nouveau remarquer que l'algorithme glouton est très rapide mais pas du tout fiable tandis que notre algorithme dynamique est très rapide en comparaison des algorithmes naïfs :
Affichage des temps d'exécution pour trouver le plus grand carré blanc dans une image
===== Test des temps pour Image_100_40_test.png =====
(5, [(63, 11), (44, 72)])
Durée Boucle For : 1.2100694179534912 secs
(5, [(63, 11), (44, 72)])
Durée Boucle While : 0.24201393127441406 secs
(3, [(3, 2)])
Durée Glouton : 0.0009999275207519531 secs
(5, [(63, 11), (44, 72)])
Durée Dynamique Itératif : 0.021001100540161133 secs
===== Test des temps pour Image_200_30_test.png =====
(6, [(60, 86)])
Durée Boucle For : 7.8124470710754395 secs
(6, [(60, 86)])
Durée Boucle While : 1.3790786266326904 secs
(3, [(6, 2), (42, 2), (60, 2), (75, 2), (84, 2), (114, 2), (126, 2)])
Durée Glouton : 0.0009999275207519531 secs
(6, [(60, 86)])
Durée Dynamique Itératif : 0.08200478553771973 secs
===== Test des temps pour Image_300_40_test.png =====
(5, [(117, 84), (223, 194), (134, 230)])
Durée Boucle For : 11.509658336639404 secs
(5, [(117, 84), (223, 194), (134, 230)])
Durée Boucle While : 2.1801247596740723 secs
(3, [(42, 2)])
Durée Glouton : 0.002000093460083008 secs
(5, [(117, 84), (223, 194), (134, 230)])
Durée Dynamique Itératif : 0.18301033973693848 secs
Vous trouverez ci-dessous un exemple de programme permettant d'obtenir ces résultats :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
|
Question n°4☘
Déterminez la complexité du code réalisé en programmation dynamique.
Une réponse
On désigne par n le nombre de pixels sur un côté de l'image. Puisque l'image est carrée, ses dimensions sont n\times n.
On appelle la fonction recherche_pgcb_iter()
.
- Cette fonction appelle la fonction
pgcb_iter()
. Danspgcb_iter()
, chaque pixel de l'image est parcouru une fois et une seule afin de compléter le tableaumemo
. Les instructions incluses dans la double bouclefor
sont toutes élémentaires donc la complexité temporelle de cette fonction est en O(n^2). - Une fois cet appel terminé, on parcourt chaque élément du tableau
memo
une fois et une seule afin de rechercher le maximum de ce tableau. Ormemo
comporte n lignes et n colonnes et les instructions incluses dans la double bouclefor
sont toutes élémentaires donc on est à nouveau en présence d'une complexité en O(n^2).
Par conséquent, la complexité temporelle de la fonction
recherche_pgcb_iter()
est en O(n^2), ce qui est bien meilleur que la
complexité des algorithmes naïf.
On peut aussi remarque que la complexité en mémoire est en O(n^2) :
elle correspond à la taille du tableau de mémoïsation memo
.
Question n°5 - Pour aller plus loin☘
Complétez le corps de la fonction suivante :
1 2 3 4 5 |
|
Un premier exemple pour tester
Avec l'image ci-contre dont la version agrandie est :
on obtient l'image dont la version agrandie est :
Un second exemple pour tester
Avec l'image ci-contre dont la version agrandie est :
on obtient l'image dont la version agrandie est :
Une solution
1 2 3 4 5 6 7 8 9 10 11 |
|