結果

問題 No.2604 Initial Motion
ユーザー pitP
提出日時 2024-01-13 01:02:11
言語 PyPy3
(7.3.15)
結果
AC  
実行時間 873 ms / 3,000 ms
コード長 8,392 bytes
コンパイル時間 275 ms
コンパイル使用メモリ 82,304 KB
実行使用メモリ 83,568 KB
最終ジャッジ日時 2024-09-28 00:55:13
合計ジャッジ時間 17,657 ms
ジャッジサーバーID
(参考情報)
judge3 / judge2
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 3
other AC * 39
権限があれば一括ダウンロードができます

ソースコード

diff #
プレゼンテーションモードにする

# https://yukicoder.me/submissions/943504
# https://atcoder.jp/contests/practice2/submissions/20654283
import heapq
class mcf_graph_int_cost:
"""It solves Minimum-cost flow problem.
"""
def __init__(self, n):
"""It creates a directed graph with n vertices and 0 edges.
Cap and Cost are the type of the capacity and the cost, respectively.
Constraints
-----------
> 0 <= n <= 10 ** 8
> Cap and Cost are int.
Complexity
----------
> O(n)
"""
self.n = n
self._edges = []
def add_edge(self, from_, to, cap, cost):
"""It adds an edge oriented from `from_` to `to` with capacity `cap` and cost `cost`.
It returns an integer k such that this is the k-th edge that is added.
Constraints
-----------
> 0 <= from_, to < n
> 0 <= cap, cost
Complexity
----------
> O(1) amortized
"""
# assert 0 <= from_ < self.n
# assert 0 <= to < self.n
# assert 0 <= cap
# assert 0 <= cost
m = len(self._edges)
self._edges.append(self.__class__.edge(from_, to, cap, 0, cost))
return m
class edge:
def __init__(self, from_, to, cap, flow, cost):
self.from_ = from_
self.to = to
self.cap = cap
self.flow = flow
self.cost = cost
def get_edge(self, i):
"""It returns the current internal state of the edges.
The edges are ordered in the same order as added by add_edge.
Constraints
-----------
> 0 <= i < m
Complexity
----------
> O(1)
"""
# assert 0 <= i < len(self._edges)
return self._edges[i]
def edges(self):
"""It returns the current internal state of the edges.
The edges are ordered in the same order as added by add_edge.
Complexity
----------
> O(m), where m is the number of added edges.
"""
return self._edges.copy()
def _dual_ref(self, s, t):
self.dist = [4611686018427387903] * self.n
self.vis = [False] * self.n
self.que_min.clear()
self.que.clear()
que_push_que = []
self.dist[s] = 0
self.que_min.append(s)
while self.que_min or self.que or que_push_que:
if self.que_min:
v = self.que_min.pop()
else:
while que_push_que:
heapq.heappush(self.que, que_push_que.pop())
v = heapq.heappop(self.que) & 9223372036854775807
if self.vis[v]:
continue
self.vis[v] = True
if v == t:
break
dual_v = self.dual[v]
dist_v = self.dist[v]
for i in range(self.start[v], self.start[v + 1]):
e = self.elist[i]
if not e.cap:
continue
cost = e.cost - self.dual[e.to] + dual_v
if self.dist[e.to] - dist_v > cost:
dist_to = dist_v + cost
self.dist[e.to] = dist_to
self.prev_e[e.to] = e.rev
if dist_to == dist_v:
self.que_min.append(e.to)
else:
que_push_que.append((dist_to << 64) + e.to)
if not self.vis[t]:
return False
for v in range(self.n):
if not self.vis[v]:
continue
self.dual[v] -= self.dist[t] - self.dist[v]
return True
def _csr(self):
m = len(self._edges)
self.edge_idx = [0] * m
redge_idx = [0] * m
degree = [0] * self.n
edges = []
for i, e in enumerate(self._edges):
self.edge_idx[i] = degree[e.from_]
degree[e.from_] += 1
redge_idx[i] = degree[e.to]
degree[e.to] += 1
edges.append((e.from_, self.__class__._edge(
e.to, -1, e.cap - e.flow, e.cost)))
edges.append((e.to, self.__class__._edge(
e.from_, -1, e.flow, -e.cost)))
self.start = [0] * (self.n + 1)
self.elist = [0] * len(edges)
for v, w in edges:
self.start[v + 1] += 1
for i in range(1, self.n + 1):
self.start[i] += self.start[i-1]
counter = self.start.copy()
for v, w in edges:
self.elist[counter[v]] = w
counter[v] += 1
for i, e in enumerate(self._edges):
self.edge_idx[i] += self.start[e.from_]
redge_idx[i] += self.start[e.to]
self.elist[self.edge_idx[i]].rev = redge_idx[i]
self.elist[redge_idx[i]].rev = self.edge_idx[i]
def slope(self, s, t, flow_limit=4611686018427387903):
"""Let g be a function such that g(x) is the cost of the minimum cost s-t flow
when the amount of the flow is exactly x.
g is known to be piecewise linear.
It returns g as the list of the changepoints, that satisfies the followings.
> The first element of the list is (0, 0).
> Both of element[0] and element[1] are strictly increasing.
> No three changepoints are on the same line.
> (1) The last element of the list is (x, g(x)), where x is the maximum amount of the s-t flow.
> (2) The last element of the list is (y, g(y)), where y = min(x, flow_limit).
Constraints
-----------
Let x be the maximum cost among all edges.
> s != t
> You can't call min_cost_slope or min_cost_max_flow multiple times.
> 0 <= nx <= 2 * 10 ** 9 + 1000
Complexity
----------
> O(F (n + m) log (n + m)), where F is the amount of the flow and m is the number of added edges.
"""
# assert 0 <= s < self.n
# assert 0 <= t < self.n
# assert s != t
self._csr()
self.dual = [0] * self.n
self.dist = [4611686018427387903] * self.n
self.prev_e = [0] * self.n
self.vis = [False] * self.n
flow = 0
cost = 0
prev_cost_per_flow = -1
result = [(0, 0)]
self.que = []
self.que_min = []
while flow < flow_limit:
if not self._dual_ref(s, t):
break
c = flow_limit - flow
v = t
while v != s:
c = min(c, self.elist[self.elist[self.prev_e[v]].rev].cap)
v = self.elist[self.prev_e[v]].to
v = t
while v != s:
e = self.elist[self.prev_e[v]]
e.cap += c
self.elist[e.rev].cap -= c
v = self.elist[self.prev_e[v]].to
d = -self.dual[s]
flow += c
cost += c * d
if prev_cost_per_flow == d:
result.pop()
result.append((flow, cost))
prev_cost_per_flow = d
for i in range(len(self._edges)):
e = self.elist[self.edge_idx[i]]
self._edges[i].flow = self._edges[i].cap - e.cap
return result
def flow(self, s, t, flow_limit=4611686018427387903):
"""It augments the flow from s to t as much as possible.
It returns the amount of the flow and the cost.
(1) It augments the s-t flow as much as possible.
(2) It augments the s-t flow as much as possible, until reaching the amount of flow_limit.
Constraints
-----------
> same as mcf_graph.slope
Complexity
----------
> same as mcf_graph.slope
"""
return self.slope(s, t, flow_limit)[-1]
class _edge:
def __init__(self, to, rev, cap, cost):
self.to = to
self.rev = rev
self.cap = cap
self.cost = cost
from collections import Counter
k,n,m = map(int,input().split())
a = Counter(map(int,input().split()))
b = list(map(int,input().split()))
g = mcf_graph_int_cost(n+2)
for i,v in a.items(): g.add_edge(0,i,v,0)
for i,v in enumerate(b,1): g.add_edge(i,n+1,v,0)
for _ in range(m):
u,v,d = map(int,input().split())
g.add_edge(u,v,2*k,d); g.add_edge(v,u,2*k,d)
print(g.flow(0,n+1)[1])
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
0