[洛谷P1407][国家集训队]稳定婚姻
题目大意:有$n$对夫妻和$m$对情人,如果一对情人中的两人都离婚了,那么他们可以结为夫妻。对于每一对夫妻,若他们离婚后所有人依然可以结婚,那么就是不安全的,否则是安全的。问每一对夫妻是否安全。
题解:考虑$tarjan$缩点。把图转成有向图,夫妻之间$G->B$,情人之间$B->G$,$tarjan$缩点,最后判断每一对夫妻是否在同一个强连通分量内($size>1$),如果在就是不安全(连成了一个环),反之安全。
卡点:1.$tarjan$中当$DFN_v$访问过时,未判断$v$是否在$stack$内
C++ Code:
#include <cstdio> #include <iostream> #include <map> #define PIS pair<int, string> #define MP make_pair #define maxn 8010 #define maxm 40010 using namespace std; map<string, int> name; int n, nn, m, name_idx; string name_p[maxn]; int head[maxn], cnt; struct Edge { int to, nxt; } e[maxm << 1]; void add(int a, int b) { e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt; } int DFN[maxn], low[maxn], stack[maxn], tot, idx; int res[maxn], res_idx, sz[maxn]; bool ins[maxn]; inline int min(int a, int b) {return a < b ? a : b;} void tarjan(int u) { int v; DFN[u] = low[u] = ++idx; ins[stack[++tot] = u] = true; for (int i = head[u]; i; i = e[i].nxt) { v = e[i].to; if (!DFN[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if (ins[v]) low[u] = min(low[u], DFN[v]); } if (DFN[u] == low[u]) { res_idx++; int siz = 0; do { ins[v = stack[tot--]] = false; res[v] = res_idx; siz++; } while (v != u); sz[res_idx] = siz; } } int main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); cin >> n; nn = n << 1; for (int i = 0; i < n; i++) { string a, b; cin >> a >> b; name_p[++idx] = a; name.insert(MP(a, idx)); name_p[++idx] = b; name.insert(MP(b, idx)); add(idx - 1, idx); } cin >> m; for (int i = 0; i < m; i++) { string a, b; cin >> a >> b; add(name[b], name[a]); } for (int i = 1; i <= nn; i++) { if (!DFN[i]) tarjan(i); } for (int i = 1; i <= n; i++) { if (sz[res[i << 1]] > 1) puts("Unsafe"); else puts("Safe"); } return 0; }