将所有现任夫妻或者前任夫妻连一条边建图,若存在环,则说明环中的所有夫妻离婚都可以找到前任,因此我们可以用tarjan算法找环,若他们在同一个连通块中则说明不安全,否则说明安全。
tarjan只能计算有向图,而一对夫妻是无向的。我们可以这样建图:
现任:男人 -> 女人
前任:女人 -> 男人
#include <map> #include <stack> #include <cstdio> #include <cstring> #include <iostream> using namespace std; const int N = 8010, M = 28010; int n, m; stack<int> stk; bool in_stk[N]; string boy, girl; int id[N], scc_cnt; map<string, int> couple; int h[N], e[M], ne[M], idx; int dfn[N], low[N], timestamp; void add(int a, int b)//邻接表 { e[idx] = b; ne[idx] = h[a]; h[a] = idx; idx ++ ; } void tarjan(int u)//tarjan算法 { dfn[u] = low[u] = ++ timestamp; stk.push(u), in_stk[u] = true; for (int i = h[u]; i != -1; i = ne[i]) { int j = e[i]; if (!dfn[j]) { tarjan(j); low[u] = min(low[u], low[j]); } else if (in_stk[j]) low[u] = min(low[u], dfn[j]); } if (dfn[u] == low[u]) { int y; scc_cnt ++ ; do { y = stk.top(); stk.pop(); in_stk[y] = false; id[y] = scc_cnt; } while (y != u); } } int main() { cin >> n; memset(h, -1, sizeof h); for (int i = 1; i <= n; i ++ ) { cin >> boy >> girl; couple[boy] = i; couple[girl] = i + n;//映射到比n大的一个数 add(couple[boy], couple[girl]);//男到女 } cin >> m; while (m -- ) { cin >> boy >> girl; add(couple[girl], couple[boy]);//女到男 } for (int i = 1; i <= n * 2; i ++ )//注意有2 * n个点 if (!dfn[i]) tarjan(i); for (int i = 1; i <= n; i ++ ) if (id[i] == id[i + n]) puts("Unsafe");//若在一个环中 else puts("Safe"); return 0; }