判断两个点是不是在一个强联通分量里面 (处理自环:只有边的x y不一样的时候才加进去)
https://www.luogu.com.cn/problem/P1407
给n个男 女关系 在给m个男 女关系 表示可能出轨的关系 如果原来的男女的关系断裂后(出轨) 是否能重新变成一个联通关系
这里使用强连通分量进行建图 对男设定为i 对应的女设为i+n 所以结果是i -> i+n
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;
unordered_map<string,int>cou;//使用字符串到数字的哈希图 转化为数字
const int N =10005, M=4e4+10;
int n,m;
int h[N], e[M], ne[M], idx;
int dfn[N],low[N],timestamp;
int stk[N],top;
bool in_stk[N];
int id[N],scc_cnt;
int din[N],dout[N];
void add(int a, int b) // 添加一条边a->b
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void tarjan(int u){
dfn[u]=low[u]=++timestamp;
stk[++top]=u,in_stk[u]=true;
for (int i = h[u]; ~i ; 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]){
++scc_cnt;
int y;
do{
y=stk[top--];
in_stk[y]=false;
id[y]=scc_cnt;
}while(y!=u);
}
}
int main()
{
cin>>n;
memset(h, -1, sizeof h);
string boy,girl;
for (int i = 1; i <= n; i ++ ){
cin>>boy>>girl;
cou[boy]=i;
cou[girl]=i+n;
add(i,i+n);
}
cin>>m;
for (int i = 1; i <= m; i ++ ){
cin>>boy>>girl;
add(cou[girl],cou[boy]);//这里反向边指回来
}
for (int i = 1; i <= 2*n; i ++ )//tarjan 遍历所有点 所以是2*n
if(!dfn[i])
tarjan(i);
for(int i=1;i<=n;i++){
if(id[i]==id[i+n]) cout<<"Unsafe"<<endl;
else cout<<"Safe"<<endl;
}
return 0;
}