Programme

Capacités attendues et commentaires

Capacités attendues

Commentaires

Programmation dynamique

Fibonnacci naif

Définition

La suite de Fibonacci est définie par :

Implémentation naïve

def fibonacci(n):
    if n == 0:
        return 0
    if n == 1:
        return 1
    return fibonacci(n-1) + fibonacci(n-2)

Arbre d’appels

fibonnacci(4)
    fibonnacci(3)
        fibonnacci(2)
            fibonnacci(1)
            fibonnacci(0)
        fibonnacci(1)
    fibonnacci(2)
        fibonnacci(1)
        fibonnacci(0)

Problème

Fibonnacci avec mémoïsation

Mémoïsation

def fibm(n, memo=None):
    if memo is None:
        memo = {0: 0, 1: 1}
    if n not in memo:
        memo[n] = fibm(n-1, memo) + fibm(n-2, memo)
    return memo[n]

Complexité avec mémoïsation

Programmation dynamique

Principe

Le terme “programmation” ne signifie pas “écrire un programme” mais “résoudre un problème”. C’est une méthode algorithmique.

Applications

Exemples

Rendu de monnaie glouton

Algorithmes gloutons

Rappel : un algorithme glouton est un algorithme qui résout un problème en faisant des choix locaux optimaux. Il ne revient pas sur ses choix.

Implémentation

def rendu_monnaie_glouton(s, pieces):
    pieces = sorted(pieces, reverse=True)
    rendu = []
    for p in pieces:
        while s >= p:
            rendu.append(p)
            s -= p
    return rendu

Problème

Il existe des cas où l’algorithme glouton ne donne pas la solution optimale, ou ne donne pas de solution du tout, alors qu’une solution existe (ici : 1 pièce de 5 cts, et 3 pièces de 2 cts).

Rendu de monnaie programmation dynamique

Principe

On peut donc écrire un algorithme récursif pour résoudre ce problème.

Attention : il faut prévoir le cas où on ne peut pas rendre la somme. CF code après.

Implémentation sans mémoïsation

def rendu_dyn(arendre, pieces):
    if arendre == 0:
        return 0, []
    best_rendu, best_rendu_len = [], float("inf")
    for piece in pieces:
        if piece <= arendre:
            clen, c = rendu_dyn(arendre - piece,
                                pieces)
            if clen < best_rendu_len:
                best_rendu = c + [piece]
                best_rendu_len = clen
    return best_rendu_len, best_rendu

rendu_dyn(11, [ 2, 5, 10, 20, 50, 100])

Implémentation avec mémoïsation

def rendu_dyn_mem(arendre, pieces, mem=None):
    if mem is None:
        mem = {0: (0, [])}
    if arendre in mem:
        return mem[arendre]
    best_rendu, best_rendu_len = [], float("inf")
    for piece in pieces:
        if piece <= arendre:
            clen, c = rendu_dyn_mem(arendre - piece,
                                    pieces, mem)
            if clen < best_rendu_len:
                best_rendu = c + [piece]
                best_rendu_len = clen
    mem[arendre] = best_rendu_len, best_rendu
    return best_rendu_len, best_rendu

rendu_dyn_mem(11,  [2, 5, 10, 20, 50, 100])