题目大意
我们已知n对夫妻的婚姻状况,称第i对夫妻的男方为Bi,女方为Gi。若某男Bi与某女Gj曾经交往过(i≠j),则当某方与其配偶(即Bi与Gi或Bj与Gj)感情出现问题时,他们有私奔的可能性。设Bi和其配偶Gi感情不和,于是Bi和Gj旧情复燃,进而Bj因被戴绿帽而感到不爽,联系上了他的初恋情人Gk……一串串的离婚事件接踵而至。若在Bi和Gi离婚的前提下,这2n个人最终依然能够结合成n对情侣,那么我们称婚姻i为不安全的,否则婚姻i就是安全的。
给定所需信息,你的任务是判断每对婚姻是否安全。
输入
第一行为一个正整数n,表示夫妻的对数;
以下n行,每行包含两个字符串,表示这n对夫妻的姓名(先女后男),由一个空格隔开;
第n+2行包含一个正整数m,表示曾经相互喜欢过的情侣对数;
以下m行,每行包含两个字符串,表示这m对相互喜欢过的情侣姓名(先女后男),由一个空格隔开。
输出
输出文件共包含n行,第i行为“Safe”(如果婚姻i是安全的)或“Unsafe”(如果婚姻i是不安全的)。
其实就是一道求强连通分量的题 建图是夫妻中girl->boy 情侣是boy->girl
若一对夫妻处在一个强连通分量里面 则婚姻就不安全 反之则安全
然后跑tarjan很快乐
刚开始老是有几个点re 把数组开的māng子一样的大之后就变成了t...
后来才发现是因为tarjan里面访问点条件写错了 是!dfn[v] 不是!vis[v]
因为如果一个强连通分量找完后出栈了就变成了false 如果又有点指向它就会再次进行访问 就可能爆掉
还有就是学到了一个很有用的东西 map 函数 其实就是不同数据类型下标的互相映射 爆好用...!!
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
const int N=100000+10;
struct person{
char name[10];
int num;
}p[N];
int idc,n,cnt,stk[N],top,tot,color[N];
int mapp,nex[2*N],tov[2*N],head[N],m,dfn[N],low[N];
char name1[10],name2[10];
bool vis[N];
void add(int u,int v){
tot++;
nex[tot]=head[u];
tov[tot]=v;
head[u]=tot;
}
int min(int a,int b){
return a<b?a:b;
}
void tarjan(int x){
dfn[x]=low[x]=++idc;
stk[++top]=x;
vis[x]=true;
for(int i=head[x];i;i=nex[i]){
int v=tov[i];
if(vis[v]){
low[x]=min(low[x],dfn[v]);
}
if(!dfn[v]){//惨痛教训
tarjan(v);
low[x]=min(low[x],low[v]);
}
}
if(low[x]==dfn[x]){
mapp++;
while(1){
int u=stk[top];
color[u]=mapp;
vis[u]=false;
top--;
if(u==x) break;
}
}
}
map<string,int> pl;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s%s",name1,name2);
pl[name1]=++cnt;
pl[name2]=++cnt;
add(cnt-1,cnt);
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%s%s",name1,name2);
add(pl[name2],pl[name1]);
}
for(int i=1;i<=cnt;i++)
if(!dfn[i]) tarjan(i);
for(int i=1;i<=n;i++){
int g=2*i-1;
int b=g+1;
if(color[b]==color[g]) printf("Unsafe\n");
else printf("Safe\n");
}
return 0;
}