加载中...

判断两个点是不是在一个强联通分量里面 (处理自环:只有边的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;
}
posted @ 2022-09-01 16:06  liang302  阅读(24)  评论(0编辑  收藏  举报