La suite de Fibonacci
p[i]+coupeRecurs(p, n-i)
max(q,p[i]+coupeRecurs(p,n-i))
Implémentation :
def coupeRecurs(n, p):
if n == 0:
return 0
else:
q = -1
for i in range (1, n+1):
q = max(q, p[i]+coupeRecurs(n-i, p))
return q
On reprend la structure à deux fonctions, la première permettant de créer le tableau de mémoïsation.
def plancheMemo(n, p):
r = [None]*(n+1)
return plancheMemoRecurs(n, p, r)
def plancheMemoRecurs(n, p, r):
if r[n]!=None:
return r[n]
elif n==0:
r[n]=0
else:
for i in range(1, n+1):
r[n]=max(r[n], p[i]+plancheMemoRecurs(n-i, p, r))
return r[n]
def plancheDynaBU(n, p):
r = [0 for i in range(n+1)]
for i in range (1, n+1):
q = 0
for j in range (1, i+1):
q = max(q, p[j]+r[i-j])
r[i] = q
return r[n]
print(renduRec(11, [100,50,10,5,2]))
>>> 4
def rendu_dyna(somme, systeme):
f=[-1]*(somme+1)
return dyna_rendu_memo(somme, systeme, f)
def dyna_rendu_memo(somme, systeme, f):
if f[somme] != -1:
return f[somme]
if somme == 0:
return 0
else:
mini = 1000
for i in range(len(systeme)):
if systeme[i] <= somme:
nb = 1 + dyna_rendu_memo(somme-systeme[i], systeme, f)
if nb < mini:
mini = nb
f[somme] = mini
return f[somme]
Complément : voila la version "bottom-up" ( donc itérative ) :
def dyna_rendu_memo_BU(somme, systeme):
# ÉTAPE 1 : création et initialisation du tableau
mem = [0]*(somme+1)
# ÉTAPE 2 : remplissage du reste du tableau par indice croissant
for i in range(1, somme + 1) :
for p in systeme :
if p <= i:
nb = 1 + mem[i-p]
if nb < mem[i]:
mem[i] = nb
# ÉTAPE 3 : le résultat est dans la dernière case
return mem[somme]
def euler_recursif(m: list[list], i, j)->int:
if i == 0 and j == 0:
return m[i][j]
elif i == 0:
return m[i][j]+euler_recursif(m, i, j-1)
elif j == 0:
return m[i][j]+euler_recursif(m, i-1, j)
else:
return m[i][j]+min(euler_recursif(m, i-1, j), euler_recursif(m, i, j-1))
m = [[131, 673, 234],
[201,96,342],
[630,803,746]]
print(euler_recursif(m, 2, 2))
def euler_memo(m: list[list])->int:
"""Cette fonction crée le tableau de mémoïsation, appelle la fonction de calcul,
et renvoie le résultat"""
h = len(m)
l = len(m[0])
phi = [[-1 for j in range(l)] for i in range(h)]
return euler_memo_calcul(m, h-1, l-1, phi)
def euler_memo_calcul(m: list[list], i: int, j: int, phi: list[list])->int:
if phi[i][j] != -1:
return phi[i][j]
if i == 0 and j == 0:
phi[i][j] = m[i][j]
elif i == 0:
phi[i][j] = m[i][j]+euler_memo_calcul(m, i, j-1, phi)
elif j == 0:
phi[i][j] = m[i][j]+euler_memo_calcul(m, i-1, j, phi)
else:
phi[i][j] = m[i][j]+min(euler_memo_calcul(m, i-1, j, phi), euler_memo_calcul(m, i, j-1, phi))
return phi[i][j]
print(euler_memo(matrix))
def euler_BU(m: list[list])->int:
"""Cette fonction crée le tableau, puis appelle la fonction de calcul,
et renvoie le résultat"""
h = len(m)
l = len(m[0])
phi = [[-1 for j in range(l)] for i in range(h)]
return euler_BU_calcul(m, phi)
def euler_BU_calcul(m: list[list], phi: list[list])->int:
for i in range(len(m)):
for j in range(len(m[0])):
if i == 0 and j == 0:
phi[i][j] = m[i][j]
elif i == 0:
phi[i][j] = m[i][j] + phi[i][j-1]
elif j == 0:
phi[i][j] = m[i][j] + phi[i-1][j]
else:
phi[i][j] = m[i][j] + min(phi[i][j-1], phi[i-1][j])
return phi[-1][-1]
m=1+min(plusGrdCarreBlancRecurs(x-1,y-1,img),plusGrdCarreBlancRecurs(x,y-1,img),plusGrdCarreBlancRecurs(x-1,y,img))
def plusGrdCarreBlancRecurs(x,y,img):
if img[x][y]==1:
return 0
elif x==0 or y==0:
return 1
else: m=1+min(plusGrdCarreBlancRecurs(x-1,y-1,img),plusGrdCarreBlancRecurs(x,y-1,img),plusGrdCarreBlancRecurs(x-1,y,img))
return m
max=0
for i in range (len(test[0])):
for j in range (len(test[0])):
print(i,j)
if plusGrdCarreBlancRecurs(i,j,test) > max:
max=plusGrdCarreBlancRecurs(i,j,test)
print('le max est ',max)
def plusGrdCarreBlancDyna1(x,y,img):
memo=[[None]*len(img[0])]*len(img[0])
return plusGrdCarreBlancMemo(x,y,img,memo)
def plusGrdCarreBlancMemo(x,y,img,memo):
if memo[x][y]!=None:
return memo[x][y]
if img[x][y]==1:
memo[x][y]=0
return memo[x][y]
elif x==0 or y==0:
memo[x][y]=1
return memo[x][y]
else:
memo[x][y] = 1+min(plusGrdCarreBlancMemo(x-1,y-1,img,memo),plusGrdCarreBlancMemo(x,y-1,img,memo),plusGrdCarreBlancMemo(x-1,y,img,memo))
return memo[x][y]
d(i, j) = 1 + d(i, j-1)
d(i, j) = 1 + d(i-1, j)
d(i, j) = d(i-1, j-1)
d(i, j) = 1 + d(i-1, j-1)
Le cas général sera de renvoyer le minimum parmi ces 4 distances possibles.
Les cas de base sont atteints lorsque :
i == - 1
) : la distance par rapport à la sous-chaîne j est alors égale au nombre de caractères de cette dernière, soit j+1.j == - 1
) : on renvoie dans ce cas i+1.
def dist_lev_rec(i, j):
if i == -1:
return j+1
if j == -1:
return i+1
if ch1[i] == ch2[j]:
cout_sub = dist_lev_rec(i-1, j-1)
else:
cout_sub = 1 + dist_lev_rec(i-1, j-1)
cout_ajout = 1 + dist_lev_rec(i-1, j)
cout_supp = 1 + dist_lev_rec(i, j-1)
return min(cout_sub, cout_ajout, cout_supp)
On peut écrire plus succinctement :
def dist_lev_rec(i, j):
if i == -1:
return j+1
if j == -1:
return i+1
cout = 0 if ch1[i] == ch2[î] else 1 # opérateur ternaire
return min(1 + dist_lev_rec(i-1, j-1), 1 + dist_lev_rec(i, j-1), cout + dist_lev_rec(i-1, j-1))
def dist_lev_TB(i, j):
if (i, j) in dist:
return dist[(i, j)]
if i == -1:
return j+1
if j == -1:
return i+1
if ch1[i] == ch2[j]:
cout_sub = dist_lev_TB(i-1, j-1)
else:
cout_sub = 1 + dist_lev_TB(i-1, j-1)
cout_ajout = 1 + dist_lev_TB(i-1, j)
cout_supp = 1 + dist_lev_TB(i, j-1)
cout_total = min(cout_sub, cout_ajout, cout_supp)
dist[(i, j)] = cout_total
return cout_total
dist est un dictionnaire initialement vide. Pour tester si une valeur a déjà été calculée auparavant, il suffit de déterminer si le couple (i, j) correspondant est déjà présent dans le dictionnaire ( complexité en O(1) ).
On constate, pour i > 0
et j > 0
, que la distance d(i, j) est le minimum entre :
1 + d(i-1, j)
,1 + d(i, j-1)
,d(i-1, j-1)
si les caractères ch1[i-1] et ch2[j-1]sont identiques,1 + d(i-1, j-1)
sinon.Par exemple :
Pour i = 2 et j = 4 ( distance entre 'CH' et 'CHUT' ) :
→ les lettres ( 'H' et 'T' ) sont différentes, donc : d(2, 4) = min(1+1, 1+2, 1+3) = min(2, 3, 4) = 2
Pour i = 4 et j = 4 ( distance entre 'CHAT' et 'CHUT' ) :
→ les lettres ( 'T' et 'T' ) sont identiques, donc : d(4, 4) = min(1+2, 0+1, 1+2) = min(3, 1, 3) = 1
La distance entre les deux chaînes ch1 et ch2 se trouve alors dans la case tout en bas à droite du tableau.
def dist_lev_BU(ch1, ch2):
m = len(ch1)
n = len(ch2)
# Initialisation du tableau
dp = [[0 for j in range(n+1)] for i in range(m+1)]
# Remplissage de la première colonne et de la première ligne
for i in range(m+1):
dp[i][0] = i
for j in range(n+1):
dp[0][j] = j
# Remplissage du tableau avec le calcul des distance pour chaque case (i, j) :
for i in range(1, m+1):
for j in range(1, n+1):
if ch1[i-1] == ch2[j-1]: # attention au décalage d'index : i = 0 ou j = 0 correspondent à une chaîne vide, pas au premier caractère des chaînes ( = indice 1 )
d1 = dp[i - 1][j - 1]
else:
d1 = 1 + dp[i - 1][j - 1]
d2 = 1 + dp[i-1][j]
d3 = 1 + dp[i][j-1]
dp[i][j] = min(d1, d2, d3)
# Renvoi de la plus petite distance :
return dp[m][n] # ou dp[-1][-1]
-->