# solutions exercices Recherche textuelle/Prog. Dyn./Diviser pour régner ### recherche textuelle #################################################### def occurrence(m, t, i): """indique s'il y a une occurrence de la chaîne m dans la chaîne t à la position i""" if i < 0 or i > len(t) - len(m): return False for j in range(len(m)): if t[i + j] != m[j]: return False return True def premiere_occurrence(m, t): """renvoie la première occurrence de m dans t, le cas échéant, et None sinon""" for i in range(0, len(t) - len(m) + 1): if occurrence(m, t, i): return i return None # table BM pour le mot "banane" # | a | b | e | n #---+---+---+---+--- # 0 | | | | # 1 | | 0 | | # 2 | 1 | 0 | | # 3 | 1 | 0 | | 2 # 4 | 3 | 0 | | 2 # 5 | 3 | 0 | | 4 # table BM pour le mot "chercher" # | c | h | e | r #---+---+---+---+--- # 0 | | | | # 1 | 0 | | | # 2 | 0 | 1 | | # 3 | 0 | 1 | 2 | # 4 | 0 | 1 | 2 | 3 # 5 | 4 | 1 | 2 | 3 # 6 | 4 | 5 | 2 | 3 # 7 | 4 | 5 | 6 | 3 # dérouler Boyer-Morre sur # recherche("chercher","chercher, rechercher et chercher encore") # La variable i prend successivement les valeurs # 0 (occurrence, qui donne le décalage 1), # 1 (qui donne le décalage 8), # 9 (décalage 3), # 12 (occurrence, décalage 1), # 13 (décalage 8), # 21 (décalage 3), # 24 (occurrence, décalage 1), # 25 (décalage 8), # 33 # # La dernière valeur prise par i est 33 et on sort # alors de la boucle car cette valeur dépasse len(t) - len(m) = 39 - 8 = 31. # # Il y a 29 # comparaisons au total (certaines positives, d'autres négatives). ### programmation dynamique ################################################ ### dérouler rendu_monnaie([1,2], 3) ######### # il y a sept appels au total : # rendu_monnaie([1,2], 3) # rendu_monnaie([1,2], 2) # rendu_monnaie([1,2], 1) # rendu_monnaie([1,2], 0) # rendu_monnaie([1,2], 0) # rendu_monnaie([1,2], 1) # rendu_monnaie([1,2], 0) # On constate qu'on a fait deux fois l'appel pour s=1 et # trois fois l'appel pour s=0. ### le tableau construit par rendu_monnaie([1, 6, 10], 12) ####### # [0, 1, 2, 3, 4, 5, 1, 2, 3, 4, 1, 2, 2] # La réponse est dans la dernière case, donc 2. ### chemins sur une grille ########## # idée : dans un tableau de tableaux grille, on stocke la réponse # pour tous les 0 <= i <= n et 0 <= j <= m def chemins(n, m): grille = [[1] * (m + 1) for _ in range(n + 1)] for i in range(1, n + 1): for j in range(1, m + 1): grille[i][j] = grille[i - 1][j] + grille[i][j - 1] return grille[n][m] ### diviser pour régner #################################################### ### rotation image ######## def rotation_aux(px, x, y, t): # On commence par traiter le cas d'une région réduite à un unique # pixel. Dans ce cas, il n'y a strictement rien à faire : if t == 1: return # Sinon, on peut découper la région en quatre sous-régions, de # dimension deux fois plus petite, dont on effectue la rotation # récursivement : t //= 2 rotation_aux(px, x , y , t) rotation_aux(px, x + t, y , t) rotation_aux(px, x , y + t, t) rotation_aux(px, x + t, y + t, t) # Il faut ensuite déplacer chacune des quatre régions, ce que l'on # peut faire élégamment avec une double boucle et une affectation # simultanée des quatre pixels qui échangent leur position : for x in range(x, x+t): for y in range(y, y+t): px[x,y+t], px[x+t,y+t], px[x+t,y ], px[x ,y] = \ px[x,y ], px[x ,y+t], px[x+t,y+t], px[x+t,y] # La rotation de l'image toute entière est obtenue avec une région qui # couvre toute l'image : def rotation(px, taille): rotation_aux(px, 0, 0, taille) ### Karatsuba ############### # Pour la fonction taille, il suffit de diviser x par deux # jusqu'à obtenir zéro. def taille(x): n = 1 while x > 0: x //= 2 n += 1 return n # Pour la fonction karatsuba, on suit l'algorithme proposé, en # s'arrêtant lorsqu'il ne reste qu'un seul chiffre. def karatsuba(x, y, n): """multiplie x et y par la méthode de Karatsuba""" 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 # Enfin, la fonction mult calcule la valeur de n comme le # maximum des deux tailles (l'algorithme reste correct si l'un des deux # entiers a moins que n chiffres). def mult(x, y): n = max(taille(abs(x)), taille(abs(y))) return karatsuba(x, y, n) # Remarque : en pratique, on ne parviendra pas à observer de progrès # par rapport à la multiplication de Python, car celle-ci repose déjà # sur une bibliothèque de grands entiers qui implémente des # algorithmes efficaces tels que Karatsuba (et même de plus efficaces # tels que Toom-Cook).