added ex2

This commit is contained in:
Louis Heredero 2025-01-28 14:32:19 +01:00
parent 70daa208d0
commit 9c6bf54f20
Signed by: HEL
GPG Key ID: 8D83DE470F8544E7
3 changed files with 114 additions and 7 deletions

View File

@ -36,7 +36,7 @@ def function1(
</tr>
</table>
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/ex1_.py)
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/Ex1.py)
/
[Tests](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/tests/test_ex1.py)
@ -46,7 +46,7 @@ def function1(
<table>
<tr>
<td><strong>But</strong></td>
<td></td>
<td>...</td>
</tr>
<tr>
<td><strong>Input</strong></td>
@ -70,7 +70,7 @@ def function2(
</tr>
</table>
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/ex2_.py)
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/Ex2.py)
/
[Tests](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/tests/test_ex2.py)
@ -104,7 +104,7 @@ def function3(
</tr>
</table>
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/ex3_.py)
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/Ex3.py)
/
[Tests](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/tests/test_ex3.py)
@ -138,7 +138,7 @@ def function4(
</tr>
</table>
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/ex4_.py)
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/Ex4.py)
/
[Tests](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/tests/test_ex4.py)
@ -172,6 +172,6 @@ def function5(
</tr>
</table>
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/ex5_.py)
[Source](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/src/Ex5.py)
/
[Tests](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/tests/test_ex5.py)

95
src/Ex2.py Normal file
View File

@ -0,0 +1,95 @@
"""
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])

View File

@ -1,8 +1,20 @@
import unittest
from Ex2 import findSafestPath
class MyTestCase(unittest.TestCase):
def test_simple1(self):
pass
self.assertEqual(
findSafestPath(0, 2, [(0, 1, -1), (1, 2, 0)]),
[0, 0, 1, 2]
)
def test_simple2(self):
self.assertEqual(
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]
)
if __name__ == '__main__':
unittest.main()