Update ugly day 16.

This commit is contained in:
Mikael CAPELLE 2022-12-16 18:40:21 +01:00
parent b1578f5709
commit 15b987a590
2 changed files with 252 additions and 110 deletions

View File

@ -1,80 +1,221 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
from __future__ import annotations
import heapq
import itertools import itertools
import re import re
import sys import sys
from collections import defaultdict
from typing import NamedTuple
from docplex.mp.model import Model from docplex.mp.model import Model
from docplex.mp.vartype import BinaryVarType
class Pipe(NamedTuple):
name: str
flow: int
tunnels: list[str]
def __lt__(self, other: object) -> bool:
return isinstance(other, Pipe) and other.name < self.name
def __eq__(self, other: object) -> bool:
return isinstance(other, Pipe) and other.name == self.name
def __hash__(self) -> int:
return hash(self.name)
def __str__(self) -> str:
return self.name
def __repr__(self) -> str:
return self.name
def breadth_first_search(pipes: dict[str, Pipe], pipe_1: Pipe, pipe_2: Pipe) -> int:
queue = [(0, pipe_1)]
visited = set()
while queue:
distance, current = heapq.heappop(queue)
if current in visited:
continue
visited.add(current)
if current == pipe_2:
return distance
for tunnel in current.tunnels:
heapq.heappush(queue, (distance + 1, pipes[tunnel]))
return -1
lines = sys.stdin.read().splitlines() lines = sys.stdin.read().splitlines()
pipes: dict[str, tuple[int, list[str]]] = {}
pipes: dict[str, Pipe] = {}
for line in lines: for line in lines:
r = re.match( r = re.match(
R"Valve ([A-Z]+) has flow rate=([0-9]+); tunnels? leads? to valves? (.+)", R"Valve ([A-Z]+) has flow rate=([0-9]+); tunnels? leads? to valves? (.+)",
line, line,
).groups() )
assert r
pipes[r[0]] = (int(r[1]), r[2].split(", ")) g = r.groups()
pipes[g[0]] = Pipe(g[0], int(g[1]), g[2].split(", "))
# compute distances from one valve to any other
distances: dict[tuple[Pipe, Pipe], int] = {}
for pipe_1 in pipes.values():
for pipe_2 in pipes.values():
distances[pipe_1, pipe_2] = breadth_first_search(pipes, pipe_1, pipe_2)
# valves with flow
relevant_pipes = [pipe for pipe in pipes.values() if pipe.flow > 0]
start_pipe = "AA" # nodes: list[tuple[Pipe, int, int, list[Pipe]]] = [(start_pipe, 0, 0, [])]
max_time = 30 # best_flow: int = 0
# while nodes:
# current, time, flow, flowing = nodes.pop(0)
# if time == max_time:
# if flow > best_flow:
# best_flow = flow
# continue
# next_nodes: list[tuple[Pipe, int, int, list[Pipe]]] = []
# for target in relevant_pipes:
# if target is current or target in flowing:
# continue
# distance = distances[current, target] + 1
# if time + distance >= max_time:
# continue
# next_nodes.append(
# (
# target,
# time + distance,
# flow + distance * sum(pipe.flow for pipe in flowing) + target.flow,
# flowing + [target],
# )
# )
# # print(time, current, flow, next_nodes)
# if not next_nodes:
# next_nodes.append(
# (
# current,
# max_time,
# flow + sum(pipe.flow for pipe in flowing) * (max_time - time - 1),
# flowing,
# )
# )
# nodes.extend(next_nodes)
# # if time >= 4:
# # break
# print(best_flow)
# nodes = [best]
# while nodes[-1].parent is not None:
# nodes.append(nodes[-1].parent)
# nodes = list(reversed(nodes))
# for node in nodes:
# print(node.time, node.valve, node.flow, node.flowing)
# #
max_time = 26 start_pipe = pipes["AA"]
ee = [0, 1] max_time = 30
ee = [0]
# max_time = 26
# ee = [0, 1]
m = Model() m = Model()
present_at = m.binary_var_dict( var_out: dict[Pipe, dict[Pipe, BinaryVarType]] = {
(e, t, pipe) for e, t, pipe in itertools.product(ee, range(max_time), pipes) pipe: m.binary_var_dict(relevant_pipes) for pipe in relevant_pipes + [start_pipe]
) }
open_at = m.binary_var_dict( var_in: dict[Pipe, dict[Pipe, BinaryVarType]] = {pipe: {} for pipe in relevant_pipes}
(e, t, pipe) for e, t, pipe in itertools.product(ee, range(max_time), pipes) for p1 in var_out:
for p2 in var_out[p1]:
var_in[p2][p1] = var_out[p1][p2]
open_at: dict[tuple[int, Pipe], BinaryVarType] = m.continuous_var_dict(
(
(t, pipe)
for t, pipe in itertools.product(range(max_time), [start_pipe] + relevant_pipes)
),
lb=0,
ub=1,
) )
for time, pipe in itertools.product(range(max_time), relevant_pipes):
m.add_constraint(open_at[time, pipe] <= m.sum())
for e in ee: for e in ee:
m.add_constraint(present_at[e, 0, start_pipe] == 1) m.add_constraint(open_at[e, 0, start_pipe] == 1)
for e, pipe in itertools.product(ee, pipes): for e, pipe in itertools.product(ee, relevant_pipes):
m.add_constraint(open_at[e, 0, pipe] == 0) m.add_constraint(open_at[e, 0, pipe] == 0)
for e, t in itertools.product(ee, range(max_time)): for e, t, p1 in itertools.product(ee, range(max_time), relevant_pipes):
m.add_constraint(m.sum(present_at[e, t, pipe] for pipe in pipes) == 1) from_time_and_pipe = [
(p2, t - distances[p2, p1] - 1)
for p2 in relevant_pipes + [start_pipe]
if t - distances[p2, p1] - 1 >= 0 and p2 is not p1
]
for e, t, pipe in itertools.product(ee, range(1, max_time), pipes): if from_time_and_pipe:
m.add_constraint( m.add_constraint(
present_at[e, t, pipe] open_at[e, t, p1]
<= present_at[e, t - 1, pipe] <= m.sum(open_at[e, t2, p2] for p2, t2 in from_time_and_pipe)
+ m.sum(present_at[e, t - 1, pipe2] for pipe2 in pipes[pipe][1])
) )
else:
m.add_constraint(open_at[e, t, p1] == 0)
for pipe2 in pipes: for pipe in relevant_pipes + [start_pipe]:
if pipe2 != pipe: m.add_constraint(
m.add_constraint(present_at[e, t, pipe] <= 1 - open_at[e, t - 1, pipe2]) m.sum(open_at[e, t, pipe] for e, t in itertools.product(ee, range(max_time)))
<= 1
for e, t, pipe in itertools.product(ee, range(1, max_time), pipes): )
m.add_constraint(open_at[e, t, pipe] <= present_at[e, t, pipe]) for e, t in itertools.product(ee, range(max_time)):
m.add_constraint(
m.sum(open_at[e, t, pipe] for pipe in relevant_pipes + [start_pipe]) <= 1
)
# keeps flowing # keeps flowing
flowing_at = m.binary_var_dict( flowing_at = {
(t, pipe) for t, pipe in itertools.product(range(max_time), pipes) (t, pipe): m.sum(
) open_at[e, t2, pipe] for e, t2 in itertools.product(ee, range(0, t))
for t, pipe in itertools.product(range(max_time), pipes):
m.add_constraint(
flowing_at[t, pipe]
== m.sum(open_at[e, t2, pipe] for e, t2 in itertools.product(ee, range(0, t)))
) )
for t, pipe in itertools.product(range(max_time), relevant_pipes)
}
# objective # objective
m.set_objective( m.set_objective(
"max", "max",
m.sum( m.sum(
flowing_at[t, pipe] * pipes[pipe][0] flowing_at[t, pipe] * pipe.flow
for t, pipe in itertools.product(range(max_time), pipes) for t, pipe in itertools.product(range(max_time), relevant_pipes)
), ),
) )
@ -84,22 +225,23 @@ s = m.solve()
print(s.get_objective_value()) print(s.get_objective_value())
# for t in range(max_time): for t in range(max_time):
# present = { opent = {
# e: [pipe for pipe in pipes if s.get_value(present_at[e, t, pipe]) > 1e-6] e: [
# for e in ee pipe
# } for pipe in relevant_pipes + [start_pipe]
# opent = { if s.get_value(open_at[e, t, pipe]) > 1e-8
# e: [pipe for pipe in pipes if s.get_value(open_at[e, t, pipe]) > 1e-6] ]
# for e in ee for e in ee
# } }
# flowing = [ flowing = [
# pipe pipe
# for pipe in pipes for pipe in relevant_pipes
# if any(s.get_value(flowing_at[e, t, pipe]) > 1e-6 for e in ee) if any(s.get_value(flowing_at[t, pipe]) > 1e-8 for e in ee)
# ] ]
# p = [present[e][0] for e in ee] assert all(len(opent[e]) <= 1 for e in ee)
# o = [opent[e][0] if opent[e] else "-" for e in ee]
# print(f"t={t}, at={p}, open={o}, flowing={flowing}") o = [opent[e][0] if opent[e] else "-" for e in ee]
print(f"t={t}, open={o}, flowing={flowing}")

View File

@ -1,64 +1,64 @@
Valve MU has flow rate=0; tunnels lead to valves VT, LA Valve AA has flow rate=0; tunnels lead to valves AM, AN, BN, LA, RJ
Valve TQ has flow rate=0; tunnels lead to valves HU, SU
Valve YH has flow rate=0; tunnels lead to valves CN, BN
Valve EO has flow rate=0; tunnels lead to valves IK, CN
Valve MH has flow rate=0; tunnels lead to valves GG, HG
Valve RJ has flow rate=0; tunnels lead to valves AA, RI
Valve XZ has flow rate=0; tunnels lead to valves PX, VT
Valve UU has flow rate=0; tunnels lead to valves DT, XG
Valve KV has flow rate=13; tunnels lead to valves HN, CV, PE, XD, TA
Valve SU has flow rate=19; tunnels lead to valves TQ, HF, OL, SF
Valve BB has flow rate=0; tunnels lead to valves NS, HR
Valve RI has flow rate=4; tunnels lead to valves ML, EE, TZ, RJ, PE
Valve TZ has flow rate=0; tunnels lead to valves VT, RI
Valve LY has flow rate=0; tunnels lead to valves EE, RP
Valve PX has flow rate=0; tunnels lead to valves XZ, JQ
Valve VH has flow rate=0; tunnels lead to valves DT, TA
Valve HN has flow rate=0; tunnels lead to valves KV, LR
Valve LR has flow rate=0; tunnels lead to valves HR, HN
Valve NJ has flow rate=0; tunnels lead to valves QF, JC
Valve AM has flow rate=0; tunnels lead to valves OJ, AA Valve AM has flow rate=0; tunnels lead to valves OJ, AA
Valve FM has flow rate=0; tunnels lead to valves VT, RP
Valve VT has flow rate=5; tunnels lead to valves IP, XZ, TZ, FM, MU
Valve HF has flow rate=0; tunnels lead to valves NR, SU
Valve HR has flow rate=11; tunnels lead to valves BB, KO, LR
Valve WX has flow rate=0; tunnels lead to valves CN, IP
Valve PE has flow rate=0; tunnels lead to valves KV, RI
Valve QF has flow rate=17; tunnels lead to valves YI, NJ
Valve EE has flow rate=0; tunnels lead to valves LY, RI
Valve UH has flow rate=25; tunnel leads to valve YI
Valve CV has flow rate=0; tunnels lead to valves KV, NS
Valve SF has flow rate=0; tunnels lead to valves YN, SU
Valve RP has flow rate=3; tunnels lead to valves HG, FM, OJ, IK, LY
Valve XD has flow rate=0; tunnels lead to valves IL, KV
Valve GG has flow rate=12; tunnels lead to valves ML, IL, MH, OL, KA
Valve XG has flow rate=0; tunnels lead to valves LI, UU
Valve YA has flow rate=21; tunnels lead to valves UJ, GQ
Valve OL has flow rate=0; tunnels lead to valves GG, SU
Valve AN has flow rate=0; tunnels lead to valves AA, IX Valve AN has flow rate=0; tunnels lead to valves AA, IX
Valve LI has flow rate=15; tunnel leads to valve XG Valve BB has flow rate=0; tunnels lead to valves NS, HR
Valve BN has flow rate=0; tunnels lead to valves AA, YH
Valve CN has flow rate=7; tunnels lead to valves YH, EO, WX, NR, OM
Valve CV has flow rate=0; tunnels lead to valves KV, NS
Valve DT has flow rate=16; tunnels lead to valves UU, HU, KA, VH
Valve EE has flow rate=0; tunnels lead to valves LY, RI
Valve EO has flow rate=0; tunnels lead to valves IK, CN
Valve FM has flow rate=0; tunnels lead to valves VT, RP
Valve GG has flow rate=12; tunnels lead to valves ML, IL, MH, OL, KA
Valve GQ has flow rate=0; tunnels lead to valves YA, KO Valve GQ has flow rate=0; tunnels lead to valves YA, KO
Valve HF has flow rate=0; tunnels lead to valves NR, SU
Valve HG has flow rate=0; tunnels lead to valves MH, RP
Valve HN has flow rate=0; tunnels lead to valves KV, LR
Valve HR has flow rate=11; tunnels lead to valves BB, KO, LR
Valve HU has flow rate=0; tunnels lead to valves TQ, DT Valve HU has flow rate=0; tunnels lead to valves TQ, DT
Valve OJ has flow rate=0; tunnels lead to valves RP, AM Valve IK has flow rate=0; tunnels lead to valves EO, RP
Valve YN has flow rate=0; tunnels lead to valves SF, JQ Valve IL has flow rate=0; tunnels lead to valves GG, XD
Valve ML has flow rate=0; tunnels lead to valves RI, GG Valve IP has flow rate=0; tunnels lead to valves WX, VT
Valve UJ has flow rate=0; tunnels lead to valves YA, NS
Valve IX has flow rate=0; tunnels lead to valves AN, JQ Valve IX has flow rate=0; tunnels lead to valves AN, JQ
Valve JC has flow rate=0; tunnels lead to valves JQ, NJ Valve JC has flow rate=0; tunnels lead to valves JQ, NJ
Valve TA has flow rate=0; tunnels lead to valves KV, VH
Valve DT has flow rate=16; tunnels lead to valves UU, HU, KA, VH
Valve NR has flow rate=0; tunnels lead to valves HF, CN
Valve YI has flow rate=0; tunnels lead to valves QF, UH
Valve AA has flow rate=0; tunnels lead to valves AM, AN, BN, LA, RJ
Valve BN has flow rate=0; tunnels lead to valves AA, YH
Valve KA has flow rate=0; tunnels lead to valves GG, DT
Valve IL has flow rate=0; tunnels lead to valves GG, XD
Valve CN has flow rate=7; tunnels lead to valves YH, EO, WX, NR, OM
Valve IP has flow rate=0; tunnels lead to valves WX, VT
Valve OM has flow rate=0; tunnels lead to valves CN, JQ
Valve KO has flow rate=0; tunnels lead to valves GQ, HR
Valve LA has flow rate=0; tunnels lead to valves AA, MU
Valve JQ has flow rate=6; tunnels lead to valves IX, JC, PX, YN, OM Valve JQ has flow rate=6; tunnels lead to valves IX, JC, PX, YN, OM
Valve IK has flow rate=0; tunnels lead to valves EO, RP Valve KA has flow rate=0; tunnels lead to valves GG, DT
Valve HG has flow rate=0; tunnels lead to valves MH, RP Valve KO has flow rate=0; tunnels lead to valves GQ, HR
Valve KV has flow rate=13; tunnels lead to valves HN, CV, PE, XD, TA
Valve LA has flow rate=0; tunnels lead to valves AA, MU
Valve LI has flow rate=15; tunnel leads to valve XG
Valve LR has flow rate=0; tunnels lead to valves HR, HN
Valve LY has flow rate=0; tunnels lead to valves EE, RP
Valve MH has flow rate=0; tunnels lead to valves GG, HG
Valve ML has flow rate=0; tunnels lead to valves RI, GG
Valve MU has flow rate=0; tunnels lead to valves VT, LA
Valve NJ has flow rate=0; tunnels lead to valves QF, JC
Valve NR has flow rate=0; tunnels lead to valves HF, CN
Valve NS has flow rate=23; tunnels lead to valves CV, BB, UJ Valve NS has flow rate=23; tunnels lead to valves CV, BB, UJ
Valve OJ has flow rate=0; tunnels lead to valves RP, AM
Valve OL has flow rate=0; tunnels lead to valves GG, SU
Valve OM has flow rate=0; tunnels lead to valves CN, JQ
Valve PE has flow rate=0; tunnels lead to valves KV, RI
Valve PX has flow rate=0; tunnels lead to valves XZ, JQ
Valve QF has flow rate=17; tunnels lead to valves YI, NJ
Valve RI has flow rate=4; tunnels lead to valves ML, EE, TZ, RJ, PE
Valve RJ has flow rate=0; tunnels lead to valves AA, RI
Valve RP has flow rate=3; tunnels lead to valves HG, FM, OJ, IK, LY
Valve SF has flow rate=0; tunnels lead to valves YN, SU
Valve SU has flow rate=19; tunnels lead to valves TQ, HF, OL, SF
Valve TA has flow rate=0; tunnels lead to valves KV, VH
Valve TQ has flow rate=0; tunnels lead to valves HU, SU
Valve TZ has flow rate=0; tunnels lead to valves VT, RI
Valve UH has flow rate=25; tunnel leads to valve YI
Valve UJ has flow rate=0; tunnels lead to valves YA, NS
Valve UU has flow rate=0; tunnels lead to valves DT, XG
Valve VH has flow rate=0; tunnels lead to valves DT, TA
Valve VT has flow rate=5; tunnels lead to valves IP, XZ, TZ, FM, MU
Valve WX has flow rate=0; tunnels lead to valves CN, IP
Valve XD has flow rate=0; tunnels lead to valves IL, KV
Valve XG has flow rate=0; tunnels lead to valves LI, UU
Valve XZ has flow rate=0; tunnels lead to valves PX, VT
Valve YA has flow rate=21; tunnels lead to valves UJ, GQ
Valve YH has flow rate=0; tunnels lead to valves CN, BN
Valve YI has flow rate=0; tunnels lead to valves QF, UH
Valve YN has flow rate=0; tunnels lead to valves SF, JQ