[洛谷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;
}
上一篇:简单C语言文法


下一篇:洛谷 P3998 [SHOI2013]发微博