bzoj2140(强连通分量tarjan)

bzoj2140
本题可转化为强连通分量来做,我们可以把每个人当作一个结点,对于每一对夫妻我们可以连一条从男士到女士的一条有向边,对于每一对情侣我们可以连一条从女士到男士的一条有向边,但是,由于每个人的编号输入的是字符串,我们可以用map<string,int>将字符串转化为数字编号。如果两个夫妻之间有环,就不安全,否则安全。
代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
#include<stack>
#include<map>
using namespace std;
const int maxn=8005;
const int maxm=30005;
map<string,int> mp;
vector<int> v[maxn];
int n,m;
int dfn[maxn],low[maxn],ins[maxn],cnt=0;
stack<int> st;
int b[maxn],c;
void tarjan(int u)
{
    dfn[u]=low[u]=++cnt;
    ins[u]=1;
    st.push(u);
    for(int i=0;i<v[u].size();i++){
        int x=v[u][i];
        if(!dfn[x]){
            tarjan(x);
            low[u]=min(low[u],low[x]);
        }
        else
        if(ins[x]){
            low[u]=min(low[u],dfn[x]);
        }
    }
    if(dfn[u]==low[u]){
        int m=0;
        while(1){
            int pre=st.top();
            st.pop();
            //printf("%d ",pre);
            m++;
            ins[pre]=0;
            b[pre]=c;
            if(pre==u)break;
        }
        //printf("\n");
        c++;
    }
}
int main()
{
    mp.clear();
    scanf("%d",&n);
    for(int i=0;i<=n;i++){
        v[i].clear();
    }
    cnt=0;
    for(int i=1;i<=n;i++){
        string s;
        cin>>s;
        int x=2*i-1;
        mp[s]=x;
        cin>>s;
        int y=2*i;
        mp[s]=y;
        v[x].push_back(y);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        string s;
        cin>>s;
        int x=mp[s];
        cin>>s;
        int y=mp[s];
        //printf("%d %d\n",x,y);
        v[y].push_back(x);
    }
    memset(dfn,0,sizeof(dfn));
    memset(ins,0,sizeof(ins));
    for(int i=1;i<=2*n;i++){
        if(!dfn[i]){
            tarjan(i);
        }
    }
    int f=0;
    for(int i=2;i<=2*n;i+=2){
        if(b[i]==b[i-1]){
            printf("Unsafe\n");
        }
        else{
            printf("Safe\n");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值