G005缩点哈密顿路径拓扑排序,竞赛进阶指南中,401题u到v或v到u路径如何确定?
摘要:从u到v还是从v到u? - AcWing 貌似数据较弱? P10944 Going from u to v or from v to u? - 洛谷 两倍经验 已知一个有向图,要求任意两点 (u, v) 都满足 (u) 可以到达
从u到v还是从v到u? - AcWing 貌似数据较弱?
P10944 Going from u to v or from v to u? - 洛谷 两倍经验
已知一个有向图,要求任意两点 \(u, v\) 都满足 \(u\) 可以到达 \(v\) 或 \(v\) 可以到达 \(u\) 。请你判断要求能不能成立。
不难看出强连通图是一定成立的,那我们就可以将图缩点成一个 DAG 然后判断源点的数量,如果源点数量大于 \(1\) 则一定不行,然后也不能出现支线,否则支线之间无法到达。
于是就变成了判断是否存在一条哈密顿路径。对于 DAG 来说其等价于拓扑排序的唯一性判断。要求每次队列中只能有一个节点
具体代码为
import sys
from collections import deque
if 1:
inp = lambda: sys.stdin.readline().strip()
II = lambda: int(inp())
MII = lambda: map(int, inp().split())
LII = lambda: list(MII())
Max = lambda x, y: x if x > y else y
Min = lambda x, y: x if x < y else y
def main():
for _ in range(II()):
n, m = MII()
g = [[] for _ in range(n + 1)]
for _ in range(m):
u, v = MII()
g[u].append(v)
dfn = [-1] * (n + 1)
low = [-1] * (n + 1)
st = []
inst = [False] * (n + 1)
scc_id = [-1] * (n + 1)
scc = 0
timer = 1
def tarjan(x):
nonlocal timer, scc
dfn[x] = low[x] = timer
timer += 1
st.append(x)
inst[x] = True
for y in g[x]:
if dfn[y] == -1:
tarjan(y)
low[x] = Min(low[x], low[y])
elif inst[y]:
low[x] = Min(low[x], dfn[y])
if dfn[x] == low[x]:
while True:
cur = st.pop()
inst[cur] = False
scc_id[cur] = scc
if cur == x:
break
scc += 1
for i in range(1, n + 1):
if dfn[i] == -1:
tarjan(i)
dag = [[] for _ in range(scc)]
din = [0] * scc
for u in range(1, n + 1):
for v in g[u]:
su = scc_id[u]
sv = scc_id[v]
if su != sv:
dag[su].append(sv)
din[sv] += 1
dq = deque([i for i in range(scc) if din[i] == 0])
f = True
while dq:
if len(dq) > 1:
f = False
break
u = dq.popleft()
for v in dag[u]:
din[v] -= 1
if din[v] == 0:
dq.append(v)
print("Yes" if f else "No")
if __name__ == "__main__":
main()
