zoukankan      html  css  js  c++  java
  • 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!
    ");
            }
            else printf("Light my fire!
    ");
        }
        return 0;
    }
  • 相关阅读:
    菜鸟学习Spring Web MVC之二
    菜鸟学习Spring Web MVC之一
    Internet Explorer 6 的15个讨厌的bug和简单的解决方法
    前端遇到的跨域问题及解决方案二
    前端遇到的跨域问题及解决方案一
    第六 添加文字
    第五章、使用预绘制图片
    第四、渐变和图案
    第三 画曲线
    第二、画线和路径
  • 原文地址:https://www.cnblogs.com/qingjiuling/p/11317454.html
Copyright © 2011-2022 走看看