L’idée :
- Nécessairement lorsque l’élément 2 fait l’aller il est avec l’élément 1.
- Si l’élément 1 a passé la berge il revient systématiquement (sauf si pas d’autres éléments à aller chercher).
Donc la première étape on fait passer 1 & 2 ensemble et revenir 1 (puisque ça va forcément se produire à un moment ou à un autre autant le faire le plus tôt possible). Coût : t[1] + t[2]
Ensuite on a deux choix :
- Prendre l’élément 1 et le plus gros élément et faire revenir 1 (et on se retrouve dans la même situation). Coût
t[1] + t[gros_element]
- Prendre les deux plus gros éléments et faire revenir 2. Coût
t[gros_element] + t[2]
On se retrouve avec dans la situation avec 1 & 2
À partir de ça on peut représenter un nœud par état
(a, b, c)
où
a
indique si l’élément 1 est présent (ça va toujours être le cas presque)
b
indique si l’élément 2 est présent
- c indique le nombre d’autres éléments restant (donc entre
len(t) - 2
et 0)
Ainsi que des arêtes entre ces nœuds, et une liste d’adjacence.
Puis on utilise dijkstra (bon dans mon implémentation c’est le dijkstra sans heapq donc avec mauvaise complexité mais on peut avoir quelque chose de satisfaisant. Avec pour nœud de départ (True, True, 0) et pour nœud d’arrive (False, False, len(t) - 2)
Normalement on a ~ (2 len(t)) nœuds et ~ 3 len(t) arcs. Donc on pourrait avoir un algo en O(n∗log(n)) où n est le nombre d’aventuriers (avec un Dijkstra propre).
import pprint
import sys
pp = pprint.PrettyPrinter(indent=4)
def traverse(t):
states = [(False, False, len(t) - 2)] + [(True, True, x) for x in range(len(t) - 1)] + [(True, False, x) for x in range(len(t) - 1)]
adj_list = {}
for state in states:
x = state[2]
if state[0] == True and state[1] == True:
if (x == len(t) - 2):
adj_list[state] = [(False, False, x, t[1], [(1, 2)])]
else:
adj_list[state] = [(True, False, x, t[1] + t[0], [(1, 2), (1)])]
elif state[0] == True and state[1] == False:
if (x == len(t) - 3):
adj_list[state] = [(False, False, x+1, t[-(x+1)], [(1, 3)])]
else:
adj_list[state] = [
(True, False, x+1, t[-(x+1)] + t[0], [(1, len(t) - x), (1)]),
(True, True, x+2, t[-(x+1)] + t[1], [(len(t) - x, len(t) - x + 1), (2)]),
]
pq = {}
for state in states:
pq[state] = (sys.maxsize, [])
pq[(True, True, 0)] = (0, [])
while(len(pq)):
min_k = None
min_v = sys.maxsize
min_pred = []
for k, (v, pred) in pq.items():
if (v <= min_v):
min_k = k
min_v = v
min_pred = pred
pq.pop(min_k)
if (min_k == (False, False, len(t) - 2)):
return min_v, min_pred
for neighbor in adj_list[min_k]:
neighbor_k = neighbor[0:3]
neighbor_cost = neighbor[3]
neighbor_pred = neighbor[4]
try:
(neighbor_current_cost, _) = pq[neighbor_k]
if (neighbor_cost + min_v < neighbor_current_cost):
pq[neighbor_k] = neighbor_cost + min_v, min_pred + neighbor_pred
except KeyError:
pass
tests = [
[10, 20, 30],
[1, 2, 5, 10],
[1, 3, 4, 6],
]
for t in tests:
pp.pprint(traverse(t))