这题题面有毒 我就不发了
对于这种毒瘤题我们先配个图
dong ma zheng gong xue cai bi chi
第一眼上去是个似乎很显然的二分图完美匹配问题
然后算了算复杂度似乎要GG(并没有验证) 于是我们去研究一下Hungary的流程
本题换一种思路 题目中给了你一组完美匹配
又给出了几组连边 其实是问你是否存在另一组完美匹配
对于样例1,我们简化一下
我们把夫妻中女方对男方连一条有向边,前女友中男方对女方连一条边
同比Hungary的流程 这里B1其实是在向G2发出申请匹配
而G2本来的匹配是B2 B2又不存在与B1的原匹配的连边 则本婚姻是稳定的
对于样例2
其实是多了一条B2向G1的连边 而G1 B1 G2 B2形成了一个增广环
所以新匹配是可以构成的
所以我们只需要Tarjan求一下强连通分量 并判断同一对夫妻中的两人是否在同一个强连通分量中即可
Tips:对于人名的处理需要Hash一下或者直接用map,否则要T.
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
#include <map>
#define travel(u) for(int i = head[u]; i; i = edge[i].next)
using namespace std;
const int MAXN = 4000 + 10;
const int MAXM = 20000 + 10;
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
map <string, int> name;
struct node { int to, next; }edge[MAXM << 1];
int head[MAXN << 1], n, m, cnt;
inline void addedge(int u, int v) {
edge[++cnt].to = v; edge[cnt].next = head[u];
head[u] = cnt;
}
stack<int> S;
int pre[MAXN << 1], lowlink[MAXN << 1], sccno[MAXN << 1];
int dfs_clock, scc_cnt;
void dfs(int u, int f) {
pre[u] = lowlink[u] = ++dfs_clock;
S.push(u);
travel(u) {
int v = edge[i].to;
if(!pre[v]) {
dfs(v, u);
lowlink[u] = min(lowlink[u], lowlink[v]);
}
else if(!sccno[v]) {
lowlink[u] = min(lowlink[u], pre[v]);
}
}
if(lowlink[u] == pre[u]) {
scc_cnt++;
for(;;) {
int x = S.top(); S.pop();
sccno[x] = scc_cnt;
if(x == u) break;
}
}
}
void tarjan() {
scc_cnt = dfs_clock = 0;
memset(pre, 0, sizeof(pre));
memset(sccno, 0, sizeof(sccno));
for(int i = 1; i <= (n << 1); ++i)
if(!pre[i]) dfs(i, 0);
}
int main() {
n = read(); char w[20], h[20];
for(int i = 1; i <= n; ++i) {
scanf("%s %s", w, h);
name[w] = i; name[h] = i + n;
addedge(i, i + n);
}
m = read();
for(int i = 1; i <= m; ++i) {
scanf("%s %s", w, h);
addedge(name[h], name[w]);
}
tarjan();
for(int i = 1; i <= n; ++i) {
if(sccno[i] == sccno[i + n]) puts("Unsafe");
else puts("Safe");
}
return 0;
}