◂ 16 décembre 2022 ▸
Proboscidea Volcanium : Ouvrir des vannes dans un réseaux dans l'ordre optimal
Valve RO has flow rate=5; tunnels lead to valves NO, FD, QV, BV
Valve GT has flow rate=0; tunn …
⋮
- graphe.png
- code.py
- codePartie1_ancienAlgo.py
- codePartie2_tropLent.py
from functools import cache
f = open("input.txt", 'r')
lines = [line[:-1] for line in f.readlines()]
START = 'AA'
TEMPS_PARTIE1 = 30
TEMPS_PARTIE2 = 26
VANNES = [] # 50 vannes au total
DEBITS = []
DISTANCES = None # tableau 50×50
for line in lines:
tokens = line.split()
vanne = tokens[1]
debit = int(tokens[4][5:-1])
VANNES.append(vanne)
DEBITS.append(debit)
DEBITS = tuple(DEBITS)
NOMBRE_VANNES_TOT = len(VANNES)
maxLongueurChemin = NOMBRE_VANNES_TOT - 1 # si graphe connexe
DISTANCES = [ (NOMBRE_VANNES_TOT * [maxLongueurChemin + 1]) for _ in VANNES]
for line in lines:
tokens = line.split()
vanne = tokens[1]
vannesTunnels = list(map(lambda s:VANNES.index(s), map(lambda s: s[-1]==',' and s[:-1] or s, tokens[9:])))
indiceVanne = VANNES.index(vanne)
for vanneTunnel in vannesTunnels:
DISTANCES[vanneTunnel][indiceVanne] = 1
DISTANCES[indiceVanne][vanneTunnel] = 1
### Calcul des distances entre tous les points du graphes, avec l'algo de
### https://fr.wikipedia.org/wiki/Algorithme_de_Floyd-Warshall
for k in range(len(VANNES)):
DISTANCES[k][k] == 0
for i in range(len(VANNES)):
for j in range(len(VANNES)):
DISTANCES[i][j] = min(DISTANCES[i][j], DISTANCES[i][k] + DISTANCES[k][j])
VANNES_UTILES = tuple([ i for i in range(len(VANNES)) if DEBITS[i] > 0])
# le cache permet de passer 60 secondes à 25 secondes d'exécution
@cache
def getChemins(vanneEnCours, vannesUtilesRestantes, tempsRestant, departChemin1=None):
chemins = []
debitSupplementaire = tempsRestant * DEBITS[vanneEnCours]
for i in range(len(vannesUtilesRestantes)):
nouvellesVannesUtilesRestantes = list(vannesUtilesRestantes[:])
prochaineVanne = nouvellesVannesUtilesRestantes.pop(i)
if departChemin1 and prochaineVanne < departChemin1: # eviter de calculer à double les répartitions symétriques entre moi et l'éléphant
continue
temps = DISTANCES[prochaineVanne][vanneEnCours] + 1
if temps >= tempsRestant:
continue
for (debitTotal, parcours) in getChemins(prochaineVanne, tuple(nouvellesVannesUtilesRestantes), tempsRestant - temps):
nouveauDebit = debitTotal + debitSupplementaire
nouveauParcours = [vanneEnCours] + parcours
chemins.append( (nouveauDebit, nouveauParcours) )
if len(chemins) == 0: # plus le temps d'aller ailleurs (ou plus de vanne restante, mais jamais le cas)
chemins = [ (debitSupplementaire, [vanneEnCours]) ] # créer un parcours qui s'arrête ici
return chemins
### Partie 1
chemins = getChemins(VANNES.index(START), VANNES_UTILES, TEMPS_PARTIE1)
meilleurDebit = max(debit for (debit, parcours) in chemins)
meilleursChemins = [[VANNES[v] for v in parcours] for (debit, parcours) in chemins if debit == meilleurDebit]
print("Réponse partie 1:", meilleurDebit, meilleursChemins)
### Partie 2
VANNES_UTILES_SET = set(VANNES_UTILES)
meilleurDebit = 0
meilleurChemin1 = None
meilleursChemins2 = None
chemins1 = getChemins(VANNES.index(START), VANNES_UTILES, TEMPS_PARTIE2)
for (debit1, parcours1) in chemins1:
departChemin1 = parcours1[0]
chemins2 = getChemins(VANNES.index(START), tuple(VANNES_UTILES_SET.difference(set(parcours1))), TEMPS_PARTIE2, departChemin1)
maxDebits2 = max(debit for (debit, parcours) in chemins2)
if debit1 + maxDebits2 >= meilleurDebit:
meilleurDebit = debit1 + maxDebits2
meilleurChemin1 = [VANNES[v] for v in parcours1]
meilleursChemins2 = [[VANNES[v] for v in parcours2] for (debit2, parcours2) in chemins2 if debit2 == maxDebits2]
print("Réponse partie 2:", meilleurDebit, meilleurChemin1, meilleursChemins2)