HDU6165 Tarjan缩点+拓扑排序

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6165

题意:给出一个有向无自环,无重边的有向图,判断任意两点是否能到达(只要一个能抵达另一个即可)

这是做的第一道拓扑排序的题目,讲解可见:https://blog.csdn.net/qq_41713256/article/details/80805338

分析:只要求两点中任一点可到达另一点即可。首先强连通分量内部肯定是可以是任意到达的,我们先利用Tarjan进行缩点形成一个有向无环图(DAG),在这个基础上我们进行拓扑排序,只要存在一条路径连接所有点的话,那么肯定是可以到达了,基于此我们在拓扑排序时,如果每一层都只有一个点入度为0 ,就可以得到唯一的一条路径连接所有点了,也就是说这时候就可以到达了。

#include<bits/stdc++.h>
#define maxn 1011
using namespace std;
vector<int>G[maxn],new_G[maxn];
stack<int>s;
int n,m;
int dfn[maxn],vis[maxn],low[maxn],color[maxn],colornum,cnt,in[maxn];
//in数组记录入度
bool toposort(int n){
    queue<int>q;
    int res=0;
    for(int i=1;i<=n;i++)  //n  节点的总数
        if(in[i]==0) q.push(i),res++;  //将入度为0的点入队列
    if(res>1) return 0;
    vector<int>ans;   //ans 为拓扑序列,这个题目里没用到 
    while(!q.empty())
    {    //cout<<233<<endl;
        int p=q.front(); q.pop(); // 选一个入度为0的点,出队列
        //cout<<p<<endl;
        ans.push_back(p);
        res=0;
        for(int i=0;i<new_G[p].size();i++)
        {    
            int y=new_G[p][i];
            //if(p==2)cout<<G[p][i]<<endl;
            in[y]--;
            if(in[y]==0)
                q.push(y),res++;
                //cout<<p<<" "<<y<<endl;  
        }
        if(res>1) return 0;
    }
    return 1;
}

void tarjan(int x)
{
    dfn[x]=low[x]=++cnt;
    s.push(x);
    vis[x]=true;
    for(int i=0;i<G[x].size();i++)
    {
        int q=G[x][i];
        if (!dfn[q])
        {
            tarjan(q);
            low[x]=min(low[x],low[q]);
        }
        else if (vis[q]) low[x]=min(low[x],dfn[q]);
    }
    if (low[x]==dfn[x])
    {
        colornum++;
        int t;
        do{
            t=s.top();s.pop();
            color[t]=colornum;
            vis[t]=false;
        }while(t!=x);
    }
}
void init(int n){
        colornum=0,cnt=0;
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(vis,0,sizeof(vis));
        memset(color,0,sizeof(color));
        memset(in,0,sizeof(in));
        for(int i=1;i<=n;i++) G[i].clear();
}
int main(){
    int T;scanf("%d",&T);
    while(T--){
        int n,m;scanf("%d%d",&n,&m);
        init(n);//初始化 
        for(int i=1;i<=m;i++){
            int x,y;scanf("%d%d",&x,&y);
            G[x].push_back(y);
        }
        for(int i=1;i<=n;i++){
            if(!dfn[i]) tarjan(i);
        }
        for(int i=1;i<=colornum;i++){//对新建的图初始化
            new_G[i].clear();
        }
        for(int i=1;i<=n;i++){
            for(int j=0;j<G[i].size();j++){
                if(color[i]!=color[G[i][j]]) in[color[G[i][j]]]++,new_G[color[i]].push_back(color[G[i][j]]);
            }
        }
        //cout<<endl<<colornum<<endl;
        if(toposort(colornum)){
            printf("I love you my love and our love save us!\n");
        }
        else printf("Light my fire!\n");
    }
    return 0;
}

 

posted @ 2019-08-07 20:02  清酒令  阅读(315)  评论(0编辑  收藏  举报