Application
Problème 1 : Rotation d'image
Entrée :
Image
Sortie :
Rotation de 90° de l'image d'entrée
Idée :
L'image à faire tourner peut être divisée en quatre carreaux qui sont déplacés d'un quart de tour, puis pivotés récursivement.

Question
Réaliser une fonction Python pour résoudre le problème 1.
Vous devrez utiliser le module PIL. Consultez le premier indice pour plus d'informations sur les fonctions nécessaires dans ce module.
Afin de faciliter le travail, les images seront carrées, et leur côté sera une puissance de 2. Par exemple, l'image smiley ci-dessous :
Si vous coincez, le deuxième indice contient un code à compléter pour vous aider.
Indice
from PIL import Image
# Pour importer une imageune_image = Image.open("lien/vers/image.png")
# Pour connaître la taille de l'imagelargeur = une_image.width
hauteur = une_image.height
# Pour connaître la valeur d'un pixelun_pixel = une_image.getpixel((x, y))
# Pour remplacer un pixel par un autreune_image.putpixel((i, j), un_pixel)
# Pour enregistrer une imageune_image.save("lien/vers/image_modif.png")
Indice
from PIL import Image
def rotation_image(image, depart_x, depart_y, taille):
# Cas de baseif taille == ???:
return # Quelle est la taille des morceaux découpés ?taille_morceau = ???
# On se retrouve avec 4 morceaux (de x à x+taille_m à x+taille, idem pour y) # On note les morceaux no (nord ouest), ne, so, sefor i in range(depart_x, depart_x + taille_morceau):
for j in range(depart_y, depart_y + taille_morceau):
# On récupère un pixel de chaque morceaupixel_no = image.getpixel(???)
pixel_ne = image.getpixel(???)
pixel_se = image.getpixel(???)
pixel_so = image.getpixel(???)
# Et on les déplace d'un morceau, dans le sens horaire.image.putpixel(???, pixel_no)
image.putpixel(???, pixel_ne)
image.putpixel(???, pixel_se)
image.putpixel(???, pixel_so)
# Ensuite, on pivote récursivement chaque morceaurotation_image(image, ???, ???, taille_morceau) # NO
rotation_image(image, ???, ???, taille_morceau) # NE
rotation_image(image, ???, ???, taille_morceau) # SE
rotation_image(image, ???, ???, taille_morceau) # SO
mon_image = Image.open("smiley.png")
rotation_image(mon_image, 0, 0, mon_image.width)
mon_image.save("smiley_edit.png")
Problème 2 : Tours de Hanoï
Entrée :
n, entier
Sortie :
déplacer n disques de la première tige à la troisième tige sachant qu'on ne déplacer qu'un disque à la fois, et qu'on ne peut pas poser un disque sur un disque plus petit
Idée :
Pour déplacer n disques de la première tour à la troisième tour, on peut déplacer n-1 disques de la première tour à la deuxième tour, déplacer le disque restant de la première tour à la troisième tour, et enfin déplacer les n-1 disques de la deuxième tour à la troisième tour.
Question
Réaliser une fonction Python pour résoudre le problème 2.
On utilisera une pile pour représenter une tour. En Python, on peut réaliser rapidement une pile avec les listes :
ma_pile = []# Création d'une pilema_pile.append(valeur)# Empiler une valeurvaleur = ma_pile.pop()# Dépiler une valeur
Les valeurs indiquent le diamètre du disque (compris entre 1 et n).
Ainsi, une liste de trois piles permet de représenter les tours de Hanoï. Le premier indice détaille en profondeur cet aspect.
Réalisez ensuite l'algorithme grâce à l'idée énoncée. Le deuxième indice propose un code à trous.
Indice
# Initialisation du jeujeu = [
[], # Première pile (pile 0) [], # Deuxième pile (pile 1) [] # Troisième pile (pile 2)]
for i in range(n, 0, -1):
# On ajoute d'abord le plus grand disque, de taille njeu[0].append(i)
Indice
def deplacer_disques(jeu, nb_disques, depart, arrivee):
""" Fonction qui déplace des disques dans le jeu de Hanoï. :param jeu: Liste des piles :param nb_disques: Nombre de disques à déplacer :param depart: Pile d'où les disques vont être pris :param arrivee: Pile où les disques vont être déplacés :return: """ # Calcul de la position intermédiaire, qui n'est ni l'arrivée ni le départif depart != 0 and arrivee != 0:
position_intermediaire = ???
elif ???:
position_intermediaire = ???
else:position_intermediaire = ???
if nb_disques == ???:
# Cas de basedisque = jeu[???].pop()
jeu[???].append(disque)
else: # On réalise l'idée du problèmedeplacer_disques(jeu, ???, ???, ???)
deplacer_disques(jeu, ???, ???, ???)
deplacer_disques(jeu, ???, ???, ???)
def hanoi(n):
# Initialisation du jeujeu = [
[], # Première pile (pile 0) [], # Deuxième pile (pile 1) [] # Troisième pile (pile 2)]
for i in range(n, 0, -1):
# On ajoute d'abord le plus grand disque, de taille njeu[0].append(i)
print(jeu)
deplacer_disques(jeu, n, 0, 2)
print(jeu)
hanoi(5)
Solution
def deplacer_disques(jeu, nb_disques, depart, arrivee):
""" Fonction qui déplace des disques dans le jeu de Hanoï. :param jeu: Liste des piles :param nb_disques: Nombre de disques à déplacer :param depart: Pile d'où les disques vont être pris :param arrivee: Pile où les disques vont être déplacés :return: """if depart != 0 and arrivee != 0:
position_intermediaire = 0
elif depart != 1 and arrivee != 1:
position_intermediaire = 1
else:position_intermediaire = 2
if nb_disques == 1:
# Cas de basedisque = jeu[depart].pop()
jeu[arrivee].append(disque)
else: # On réalise l'idée du problèmedeplacer_disques(jeu, nb_disques-1, depart, position_intermediaire)
deplacer_disques(jeu, 1, depart, arrivee)
deplacer_disques(jeu, nb_disques-1, position_intermediaire, arrivee)
def hanoi(n):
# Initialisation du jeujeu = [
[], # Première pile (pile 0) [], # Deuxième pile (pile 1) [] # Troisième pile (pile 2)]
for i in range(n, 0, -1):
# On ajoute d'abord le plus grand disque, de taille njeu[0].append(i)
print(jeu)
deplacer_disques(jeu, n, 0, 2)
print(jeu)
hanoi(5)
Problème 3 : Multiplication
Entrées :
x, y entiers en binaire de taille \(2 \times n\)
Sortie :
\(x \times y\) en utilisant l'algorithme de Karatsuba
Idée :
Normalement, pour multiplier deux nombres, on multiplie chaque chiffre de x par y, en décalant avec un zéro, puis on additionne les résultats obtenus.
Se renseigner sur la page Wikipédia.
Question
Réaliser une fonction Python pour résoudre le problème 3.
On utilisera des entiers, mais uniquement des opérateurs binaires :
bin(x) # Affiche l'écriture binaire de x
x<<n # Décale l'écriture de x en binaire vers la gauche en rajoutant des zéros
x>>n # Décale l'écriture de x en binaire vers la droite (et donc supprime des bits)
Vous pouvez débuter par calculer le nombre de bits d'un nombre entier. Voir solution 1.
Ensuite, il faut calculer les différentes valeurs a, b, c et d nécessaires à l'algorithme de Karatsuba. Vous pouvez consulter le premier indice pour vous aider à les calculer.
Enfin, il ne reste plus qu'à calculer récursivement les différentes valeurs nécessaires au calcul final. Voir solution 2.
Indice
Si x = 1001 1011 1001 0011, alors a = 1001 1011 et b = 1001 0011.
Ainsi, pour calculer la valeur de a, on doit supprimer les 8 derniers bits (avec l'opérateur >>) et pour calculer b, on doit supprimer les 8 premiers bits grâce au modulo % et à un nombre bien choisi.
Solution
def taille(x):
""" Taille du nombre binaire x :param x: :return: """n = 1
while x > 0:
x >>= 1
n += 1
return n
Solution
def karatsuba(x, y, n):
""" Réalise la multiplication x*y avec x et y de taille n :param x: :param y: :param n: Taille max entre x et y :return: """if n <= 1:
return x * y
n //= 2
m = 1 << n
a, b = x >> n, x % m
c, d = y >> n, y % m
ac = karatsuba(a, c, n)
bd = karatsuba(b, d, n)
abcd = karatsuba(a - b, c - d, n)
return (ac << (2*n)) + ((ac + bd - abcd) << n) + bd
def taille(x):
""" Taille du nombre binaire x :param x: :return: """n = 1
while x > 0:
x >>= 1
n += 1
return n
def mult(x, y):
n = max(taille(x), taille(y))
return karatsuba(x, y, n)
print(mult(42, 69), 42*69)
