P1407
题目:P1407
n对夫妻之间有m对前男女友关系,问第i对婚姻是否稳定(即第i对夫妻离婚后2n个人能不能组成n对夫妻)
我们思考他们爱恨纠葛组合的这个过程(假设女方劈腿):
男一女一离婚,女一去找男二,导致女二很生气去找了男三……总之一定会有一个女n号找到男一并组成夫妻。
那这个过程就很像一个环了:从男一出发到女一、男二、女二、男三……女n,男一。
我们可以模拟这个过程,即如果是夫妻关系就从男到女建边,前男女朋友关系从女到男建边。如果形成一个刚才那样的环的话,环里的几对夫妻的婚姻都是不稳定的(不管哪一对夫妻感情不合,都能通过这个环找到自己的旧日情人)
反之,如果某对夫妻形不成环,那就算是离婚,男方也找不到另一个前女友和自己结婚(否则就能形成环,矛盾)
那tarjan算法求强连通分量就可以解决这个问题:如果强连通分量中只有一个点,那这个点所在夫妻婚姻稳定;如果有多个点,那这个强连通分量里的所有夫妻婚姻都是不稳定的。
可以证明,对于一对夫妻(b,g)来说,它们只可能同时出现在一个强连通分量中,或是分别在两个只有一个点的强连通分量中。
(因为原图是二分图,无奇环,如果他们分别在两个具有多个点的强连通分量(或是其中一个有多个点,另一个只有一个点)中,那其中有多个点的强连通分量中要么多一个男生或女生,要么会有一对不是夫妻的男女由于强连通分量要有环的关系必须建夫妻边)
总之我们夫妻边建男到女的边,前情侣边建女到男的边,然后跑tarjan判断有无环,有环则环里的夫妻为不稳定婚姻,反之若夫妻不在环里则为稳定婚姻。
代码:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=8888;
const int M=2e4+4;
int n,m,awa,dfn[2*N],low[2*N],vis[2*N],CP[N],h[2*N],tot;
char b[15],g[15];
stack<int> st;
map<string,int> mp;//用map将名字转为点编号
struct sw{
int u,v,nxt;
}e[N+M];
void add(int u,int v){
e[++tot]={u,v,h[u]};
h[u]=tot;
}
void tar(int u){//求强连通分量
dfn[u]=low[u]=++awa;
vis[u]=1;
st.push(u);
for(int i=h[u];i;i=e[i].nxt){
int v=e[i].v;
if(!dfn[v]){
tar(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(dfn[u]==low[u]){
int owo=0;
int cnt=0;
do{
cnt++;
owo=st.top();
//printf("out %d\n",owo);
int cp=owo%n;
if(cp==0){
cp=n;
}
if(cnt>1){//有多对夫妻参与的强连通分量中,每对夫妻的婚姻都不稳定
CP[cp]=1;
}
vis[owo]=0;
st.pop();
}while(owo!=u);
}
}
int main(){
scanf("%d",&n);
//这里我建了2n个点,1~n为男,n+1~2n为女
for(int i=1;i<=n;i++){
scanf("%s%s",g,b);
mp[b]=i;mp[g]=n+i;
add(i,n+i);
//cout<<i<<"->"<<n+i<<endl;
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%s%s",g,b);
add(mp[g],mp[b]);
//cout<<mp[g]<<"->"<<mp[b]<<endl;
}
for(int i=1;i<=2*n;i++){
if(dfn[i]){
continue;
}
tar(i);
}
for(int i=1;i<=n;i++){
if(CP[i]==1){
printf("Unsafe\n");
}
else if(CP[i]==0){
printf("Safe\n");
}
}
return 0;
}

浙公网安备 33010602011771号