TP : révisions d’informatique commune 1ère année#

Si vous avez besoin de rappels, regarder mon cours de première année.

Représentation des nombres#

Exercice

Ecrire une fonction to_base10(L, b) qui renvoie l’entier (en base 10) qui s’écrit en base \(b\) avec les chiffres de la liste L.
Par exemple, to_base10([0, 0, 1, 1], 2) doit renvoyer \(2^2 + 2^3 = 12\).

to_base10([0, 0, 1, 1], 2)
12

Exercice

Ecrire une fonction from_base10(n, b) qui renvoie la liste des chiffres de l’entier n en base b.

from_base10(12, 2)
[0, 0, 1, 1]

Exercice

Quelle valeur donne 0.1 + 0.1 + 0.1 ? Expliquer pourquoi.

Exercice

Quelle valeur donne 2.0**53 + 1.0 - 2.0**53 ? 2.0**52 + 1.0 - 2.0**52 ? Expliquer.

Dichotomie#

Exercice

Ecrire une fonction dichotomie(L, e) qui renvoie True si e est dans la liste triée L et False sinon, en complexité \(O(\log n)\). Justifier la complexité.

def dichotomie(e, L):
        i, j = 0, len(L) - 1  # i et j sont les indices de L entre lesquels on cherche e
        while ...: # tant qu'il reste au moins 1 élément entre les indices i et j
                m = ... # milieu de i et j
                if e < L[m]:
                        ... # regarder dans la partie gauche
                elif e > L[m]:
                        ... # regarder dans la partie droite
                else:
                        ... # on a trouvé e
        ... # e n'a pas été trouvé
dichotomie([1, 2, 3, 4, 5, 6, 7, 8, 9], 5) and not dichotomie([1, 2, 3, 4, 5, 6, 7, 8, 9], 10)
True

Exercice

Donner un invariant de boucle permettant de prouver la correction de la fonction dichotomie.

Graphes#

Exercice

Ecrire une fonction mat_to_adj(M) qui convertit une matrice d’adjacence M en liste d’adjacence.

Exercice

Ecrire une fonction dfs(G, s) qui renvoie la liste des sommets visités par un parcours en profondeur du graphe G depuis le sommet s. G est représenté par une liste d’adjacence.

def dfs(G, s):
    # définir une liste de booléens pour savoir si un sommet a été visité
    def aux(u): # fonction récursive
        # si u n'a pas été visité :
            # afficher u
            # marquer u comme visité
            # pour chaque voisin v de u
                # appeler aux(v)
    aux(s)
  Cell In [9], line 9
    aux(s)
    ^
IndentationError: expected an indented block
dfs([[1, 4], [0, 2], [], [0, 1], [], []], 0)
0
1
2
4

Exercice

Expliquer l’intérêt et le fonctionnement d’un parcours en largeur.

Dijkstra#

On rappelle qu’une file de priorité (min) est une structure de donnée permettant de récupérer efficacement l’élément de plus petite priorité. On définit le type suivant de file de priorité :

class PriorityQueue:
    def __init__(self) -> None:
        self.d = dict()

    def update(self, element, priority):
        self.d[element] = priority

    def add(self, element, priority):
        self.d[element] = priority

    def take_min(self):
        k_min = None
        for k in self.d:
            if k_min is None or self.d[k] < self.d[k_min]:
                k_min = k
        self.d.pop(k_min)
        return k_min

    def is_empty(self):
        return len(self.d) == 0

    def __contains__(self, element):
        return element in self.d

Il n’est pas nécessaire de comprendre ce code, juste de savoir l’utiliser :

q = PriorityQueue() # file de priorité vide
q.add(0, 6) # ajoute l'élément 0 avec une priorité de 6
q.add(1, 3)
q.add(2, 5)
q.take_min() # renvoie l'élément de priorité min, ici 1
q.update(0, 2) # met à jour la priorité de l'élément 0 à 2
q.take_min()
q.add(3, 7)
q.take_min()
2

Exercice

Rappeler à quoi sert l’algorithme de Dijkstra et quelle condition le graphe doit vérifier pour que l’algorithme fonctionne.

Exercice

Compléter la fonction suivante pour implémenter l’algorithme de Dijkstra permettant de trouver les distances de \(s\) aux autres sommets de \(G\). \(G\) est représenté par une matrice d’adjacence pondérée (G[i][j] est le poids de l’arête entre \(i\) et \(j\), float('inf') s’il n’y a pas d’arête).
Tester sur un graphe de votre choix.

def dijkstra(G, s):
    n = ... # nombre de sommets de G
    dist = ... # créer une liste de taille n remplie de float("inf")
    dist[s] = 0
    q = PriorityQueue()
    # ajouter chaque sommet v de G à q, avec comme priorité dist[v]
    while ...: # tant que q n'est pas vide
        u = ... # extraire de q le sommet de priorité minimum
        for v in range(n): # pour chaque voisin de u
            d = dist[u] + G[u][v]
            if v in q and ...: # si d < dist[v]
                ... # mettre à jour dist[v] et la priorité de v
    return dist

Exercice

Résoudre cet exercice.

A*#

l’algorithme A* permet de trouver un plus court chemin d’un sommet \(s\) à un sommet \(t\) fixé dans un graphe \(G\) (contrairement à Dijkstra, qui trouve le plus court chemin de \(s\) à tous les sommets). Il est plus rapide que Dijkstra si une bonne heuristique est utilisée.

Principe de l’algorithme A* :

  1. Définir une fonction \(h\) telle que \(h(v)\) soit une estimation de la distance de \(v\) à \(t\).

  2. Modifier l’algorithme de Dijkstra en utilisant dist[u] + G[u][v] + h(v) comme priorité, au lieu de dist[u] + G[u][v].

Exercice

Modifier la fonction dijkstra pour implémenter l’algorithme A*.

Exercice

Si les sommets du graphes sont des points du plan \(\mathbb{R}^2\), quelle heuristique \(h\) serait-il raisonnable d’utiliser pour trouver le plus court chemin entre deux points ? Plusieurs réponses sont possibles.