結果
問題 | No.519 アイドルユニット |
ユーザー |
![]() |
提出日時 | 2022-05-21 19:41:46 |
言語 | PyPy3 (7.3.15) |
結果 |
AC
|
実行時間 | 182 ms / 1,000 ms |
コード長 | 9,994 bytes |
コンパイル時間 | 151 ms |
コンパイル使用メモリ | 81,920 KB |
実行使用メモリ | 75,904 KB |
最終ジャッジ日時 | 2024-09-20 12:07:20 |
合計ジャッジ時間 | 3,536 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 34 |
ソースコード
INF = 1 << 60from collections import dequeclass GeneralWeightedMatching():def __init__(self, n):self.n = nself.nx = nself.m = 2 * n + 1self.u = [0] * self.m * self.mself.v = [0] * self.m * self.mself.w = [0] * self.m * self.mself.match = [0] * self.mself.slack = [0] * self.mself.flower = [[] for _ in range(self.m)]self.flower_from = [0] * self.m * self.mself.label = [0] * self.mself.root = [0] * self.mself.par = [0] * self.mself.col = [0] * self.mself.vis = [0] * self.mself.que = deque()self.t = 0for u in range(1, self.m):for v in range(1, self.m):self.u[u * self.m + v] = uself.v[u * self.m + v] = vdef dist(self, u, v):u, v = self.u[u * self.m + v], self.v[u * self.m + v]return self.label[u] + self.label[v] - self.w[u * self.m + v] * 2def add_edge(self, u, v, w):u += 1; v += 1self.w[u * self.m + v] = max(self.w[u * self.m + v], w)self.w[v * self.m + u] = max(self.w[v * self.m + u], w)def update_slack(self, u, x):if not self.slack[x] or self.dist(u, x) < self.dist(self.slack[x], x):self.slack[x] = udef set_slack(self, x):self.slack[x] = 0for u in range(1, self.n + 1):if self.w[u * self.m + x] > 0 and self.root[u] != x and self.col[self.root[u]] == 0:self.update_slack(u, x)def que_push(self, x):stack = [x]while stack:x = stack.pop()if x <= self.n:self.que.append(x)continuefor i, fi in enumerate(self.flower[x]):stack.append(fi)def set_root(self, x, b):stack = [x]while stack:x = stack.pop()self.root[x] = bif x <= self.n:continuefor i, fi in enumerate(self.flower[x]):stack.append(fi)def get_pr(self, b, xr):f = self.flower[b]pr = f.index(xr)if pr % 2 == 1:f = self.flower[b] = f[0:1] + f[1:][::-1]return len(f) - prelse:return prdef set_match(self, u, v):self.match[u] = self.v[u * self.m + v]if u <= self.n:returnxr = self.flower_from[u * self.m + self.u[u * self.m + v]]pr = self.get_pr(u, xr)f = self.flower[u]for i in range(pr):self.set_match(f[i], f[i ^ 1])self.set_match(xr, v)self.flower[u] = f[pr:] + f[:pr]def augment(self, u, v):xnv = self.root[self.match[u]]self.set_match(u, v)while xnv:self.set_match(xnv, self.root[self.par[xnv]])u, v = self.root[self.par[xnv]], xnvxnv = self.root[self.match[u]]self.set_match(u, v)def get_lca(self, u, v):self.t += 1while u or v:if not u:u, v = v, ucontinueif self.vis[u] == self.t:return uself.vis[u] = self.tu = self.root[self.match[u]]if u: u = self.root[self.par[u]]u, v = v, ureturn 0def add_blossom(self, u, lca, v):b = self.n + 1while b <= self.nx and self.root[b]:b += 1if b > self.nx:self.nx += 1self.label[b] = 0self.col[b] = 0self.match[b] = self.match[lca]f = self.flower[b] = []f.append(lca)x = uwhile x != lca:f.append(x)y = self.root[self.match[x]]f.append(y)self.que_push(y)x = self.root[self.par[y]]f = self.flower[b] = f[0:1] + f[1:][::-1]x = vwhile x != lca:f.append(x)y = self.root[self.match[x]]f.append(y)self.que_push(y)x = self.root[self.par[y]]self.set_root(b, b)for x in range(1, self.nx + 1):self.w[b * self.m + x] = self.w[x * self.m + b] = 0for x in range(1, self.n + 1):self.flower_from[b * self.m + x] = 0for i, xs in enumerate(f):for x in range(1, self.nx + 1):if self.w[b * self.m + x] == 0 or self.dist(xs, x) < self.dist(b, x):self.u[b * self.m + x] = self.u[xs * self.m + x]self.u[x * self.m + b] = self.u[x * self.m + xs]self.v[b * self.m + x] = self.v[xs * self.m + x]self.v[x * self.m + b] = self.v[x * self.m + xs]self.w[b * self.m + x] = self.w[xs * self.m + x]self.w[x * self.m + b] = self.w[x * self.m + xs]for x in range(1, self.n + 1):if self.flower_from[xs * self.m + x]:self.flower_from[b * self.m + x] = xsself.set_slack(b)def expand_blossom(self, b):f = self.flower[b]for i, fi in enumerate(f):self.set_root(fi, fi)xr = self.flower_from[b * self.m + self.u[b * self.m + self.par[b]]]pr = self.get_pr(b, xr)f = self.flower[b]for i in range(0, pr, 2):xs = f[i]xns = f[i + 1]self.par[xs] = self.u[xns * self.m + xs]self.col[xs] = 1self.col[xns] = 0self.slack[xs] = 0self.set_slack(xns)self.que_push(xns)self.col[xr] = 1self.par[xr] = self.par[b]for i in range(pr + 1, len(f)):xs = f[i]self.col[xs] = -1self.set_slack(xs)self.root[b] = 0def on_found_edge(self, u, v):eu = self.u[u * self.m + v]ev = self.v[u * self.m + v]u = self.root[eu]v = self.root[ev]if self.col[v] == -1:self.par[v] = euself.col[v] = 1nu = self.root[self.match[v]]self.slack[v] = self.slack[nu] = 0self.col[nu] = 0self.que_push(nu)elif self.col[v] == 0:lca = self.get_lca(u, v)if not lca:self.augment(u, v)self.augment(v, u)return 1else:self.add_blossom(u, lca, v)return 0def matching(self):for i in range(self.nx + 1):self.col[i] = -1self.slack[i] = 0self.que.clear()for x in range(1, self.nx + 1):if self.root[x] == x and not self.match[x]:self.par[x] = 0self.col[x] = 0self.que_push(x)if not self.que:return 0while True:while self.que:u = self.que.popleft()if self.col[self.root[u]] == 1:continuefor v in range(1, self.n + 1):if self.w[u * self.m + v] and self.root[u] != self.root[v]:if self.dist(u, v) == 0:if self.on_found_edge(u, v):return 1else:self.update_slack(u, self.root[v])d = INFfor b in range(self.n + 1, self.nx + 1):if self.root[b] == b and self.col[b] == 1:d = min(d, self.label[b] // 2)for x in range(1, self.nx + 1):if self.root[x] == x and self.slack[x]:if self.col[x] == -1:d = min(d, self.dist(self.slack[x], x))elif self.col[x] == 0:d = min(d, self.dist(self.slack[x], x) // 2)for u in range(1, self.n + 1):if self.col[self.root[u]] == 0:if self.label[u] <= d:return 0self.label[u] -= delif self.col[self.root[u]] == 1:self.label[u] += dfor b in range(self.n + 1, self.nx + 1):if self.root[b] == b:if self.col[b] == 0:self.label[b] += d * 2elif self.col[b] == 1:self.label[b] -= d * 2self.que.clear()for x in range(1, self.nx + 1):if self.root[x] == x and self.slack[x] and self.root[self.slack[x]] != x and self.dist(self.slack[x], x) == 0:if self.on_found_edge(self.slack[x], x):return 1for b in range(self.n + 1, self.nx + 1):if self.root[b] == b and self.col[b] == 1 and self.label[b] == 0:self.expand_blossom(b)return 0def solve(self):cnt = 0ans = 0for u in range(self.n + 1):self.root[u] = uself.flower[u].clear()w_max = 0for u in range(1, self.n + 1):for v in range(1, self.n + 1):self.flower_from[u * self.m + v] = u if u == v else 0w_max = max(w_max, self.w[u * self.m + v])for u in range(1, self.n + 1):self.label[u] = w_maxwhile self.matching():cnt += 1for u in range(1, self.n + 1):if self.match[u] and self.match[u] < u:ans += self.w[u * self.m + self.match[u]]for i in range(self.n):self.match[i] = self.match[i + 1] - 1return ans, cntN = int(input())F = [list(map(int, input().split())) for _ in range(N)]G = GeneralWeightedMatching(N)for i in range(N - 1):for j in range(i + 1, N):G.add_edge(i, j, F[i][j])res, _ = G.solve()print(res)