added ex2
This commit is contained in:
		
							
								
								
									
										12
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								README.md
									
									
									
									
									
								
							| @@ -36,7 +36,7 @@ def function1( | |||||||
| </tr> | </tr> | ||||||
| </table> | </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) | [Tests](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/tests/test_ex1.py) | ||||||
|  |  | ||||||
| @@ -46,7 +46,7 @@ def function1( | |||||||
| <table> | <table> | ||||||
| <tr> | <tr> | ||||||
| <td><strong>But</strong></td> | <td><strong>But</strong></td> | ||||||
| <td></td> | <td>...</td> | ||||||
| </tr> | </tr> | ||||||
| <tr> | <tr> | ||||||
| <td><strong>Input</strong></td> | <td><strong>Input</strong></td> | ||||||
| @@ -70,7 +70,7 @@ def function2( | |||||||
| </tr> | </tr> | ||||||
| </table> | </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) | [Tests](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/tests/test_ex2.py) | ||||||
|  |  | ||||||
| @@ -104,7 +104,7 @@ def function3( | |||||||
| </tr> | </tr> | ||||||
| </table> | </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) | [Tests](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/tests/test_ex3.py) | ||||||
|  |  | ||||||
| @@ -138,7 +138,7 @@ def function4( | |||||||
| </tr> | </tr> | ||||||
| </table> | </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) | [Tests](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/tests/test_ex4.py) | ||||||
|  |  | ||||||
| @@ -172,6 +172,6 @@ def function5( | |||||||
| </tr> | </tr> | ||||||
| </table> | </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) | [Tests](https://git.kb28.ch/HEL/AlgoDS-Examen2025/src/branch/main/tests/test_ex5.py) | ||||||
|   | |||||||
							
								
								
									
										95
									
								
								src/Ex2.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/Ex2.py
									
									
									
									
									
										Normal 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]) | ||||||
| @@ -1,8 +1,20 @@ | |||||||
| import unittest | import unittest | ||||||
|  |  | ||||||
|  | from Ex2 import findSafestPath | ||||||
|  |  | ||||||
|  |  | ||||||
| class MyTestCase(unittest.TestCase): | class MyTestCase(unittest.TestCase): | ||||||
|     def test_simple1(self): |     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__': | if __name__ == '__main__': | ||||||
|     unittest.main() |     unittest.main() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user