""" Nom/Prénom: Heredero/Louis Explications: Tout d'abord, le réseau de routes et d'intersections peut être représenté par un graphe, dans lequel les interséctions sont les nœuds et les routes les arêtes. Ainsi, nous cherchons à trouver le chemin le plus court du point de départ au point d'arrivée, tel que les routes marquées 1 ne soient parcourues que de jour (c'est-à-dire si leurs index dans le chemin parcouru est pair), et celles marquées -1 seulement de nuit (index impair). En plus des routes données, nous pouvons aussi rester sur un même nœud pour une nuit. Afin de bien gérer les différences d'états entre jour et nuit, nous pouvons intégrer le demi-jour associé à chaque visite de nœud. Ainsi, une même intersection peut avoir deux nœud: un pour une visite de jour, et un de nuit. Pour résoudre ce problème, comme nous ne pouvons pas établir d'heuristique mesurant notre distance au point d'arrivée, nous pouvons utiliser un algorithme BFS assez simple: - Initialiser la liste des nœuds à traiter avec le nœud de départ et le demi-jour de départ (`DAY`) - Tant que nous n'avons pas trouvé le nœud d'arrivée: - Pour chaque nœud à traiter : - Visiter les nœuds voisins non visités (liés par une route praticable) - Indiquer pour chaque voisin son parent - L'ajouter à la nouvelle liste des nœuds à traiter - Alterner le demi-jour courant - Recommencer avec la nouvelle liste de nœuds à traiter """ from typing import Optional ALWAYS = 0 DAY = 1 NIGHT = -1 def get_path(visited: dict[tuple[int, int], Optional[int]], end: int, end_time: int) -> list[int]: path: list[int] = [] parent: Optional[int] = end time: int = end_time while parent is not None: path.append(parent) parent = visited[(parent, time)] time = -time return list(reversed(path)) def findSafestPath(start: int, end: int, intersections: list[tuple[int, int, int]]) -> list[int]: edges: dict[int, dict[int, set[int]]] = { ALWAYS: {}, DAY: {}, NIGHT: {} } for i1, i2, mode in intersections: edge_dict: dict[int, set[int]] = edges[mode] if i1 not in edge_dict: edge_dict[i1] = set() if i2 not in edge_dict: edge_dict[i2] = set() edge_dict[i1].add(i2) edge_dict[i2].add(i1) visited: dict[tuple[int, int], Optional[int]] = { (start, DAY): None } to_process: list[int] = [start] time = DAY while len(to_process) != 0: to_process2 = [] time2 = -time for idx in to_process: always: set[int] = edges[ALWAYS].get(idx, set()) matching_time: set[int] = edges[time].get(idx, set()) neighbors: set[int] = always | matching_time neighbors.add(idx) for neighbor in neighbors: key = (neighbor, time2) # Skip if already visited if key in visited: continue visited[key] = idx if neighbor == end: return get_path(visited, end, time2) to_process2.append(neighbor) to_process = to_process2 time = time2 return [] if __name__ == '__main__': print(findSafestPath(0,2,[(0, 1, -1), (1, 2, 0)]) == [0, 0, 1, 2]) print(findSafestPath(0, 5, [(0,1,0), (0,2,1), (2,1,-1), (1,3,-1), (2,4,-1), (3,5,1), (3,4,0), (4,5,-1)]) == [0, 1, 3, 5])