zoukankan      html  css  js  c++  java
  • poj2767,单向连通图判定,缩点+重新建图+新图DFS

    /*该题被博客里标记为中等题,30分钟内1A,掌握了算法就简单了,单向连通图判定,单向连通图缩点
    后必然唯一存在出度为0的点和入度为0的点,并且从入度为0的点出发,可以遍历所有点后到达出度为0点
    (一条长链),(容易反证),所以缩点后,我重新建图(以前觉得重新建图好麻烦,现在看来SO easy),
    ,对新有向无环图,从入度为0的点做dfs(回溯时要标记回来,因为要所有dfs路线),有一条深度到达
    强连通分支数即为yes,反之no*/
    #include<iostream>  //297MS, 1A,简单题。
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<stack>
    using namespace std;
    int n;int m;
    const int MAX=1001;
    vector<vector<int> >edges(MAX);  //原图
    vector<vector<int> >newedge(MAX);//缩点后图
    int visited[MAX];             //原图tarjan
    int low[MAX];
    int dfn[MAX];
    bool mark[MAX];                //新图dfs标记
    int Strongly_connected_branch[MAX];   //并为一个强连通,标记为1.2.3...
    int num;int times;      
    stack<int>s;            
    bool instack[MAX];
    int ind[MAX];         //入度数组
    void tarjan(int u)
    {
        low[u]=dfn[u]=times++;
        instack[u]=1;
        s.push(u);
        int len=edges[u].size();
        for(int i=0;i<len;i++)
        {
            int v=edges[u][i];
            if(visited[v]==0)
            {
                 visited[v]=1;
                   tarjan(v);
                if(low[u]>low[v])low[u]=low[v];
            }
            else if(instack[v]&&low[u]>dfn[v])   //有向图,要问是否在栈中,后向边,V为U某个祖先
            {
                low[u]=dfn[v];
            }
        }
        if(dfn[u]==low[u])          //在一个SCC
        {
            num++;int temp;
             do
            {
                 temp=s.top();
                 instack[temp]=0;
                s.pop();
                Strongly_connected_branch[temp]=num;
            } while(temp!=u);
        }
    }
    bool is_no; 
    void dfs(int u,int depth)      //新图的dfs
    {
        if(depth==num)is_no=true;
        int len=newedge[u].size();
        for(int i=0;i<len;i++)
        {
            int v=newedge[u][i];
            if(mark[v]==0)
              {
                  mark[v]=1;
                  dfs(v,depth+1);
                  mark[v]=0;
              }
        }
    }
    void readin()
    {
        scanf("%d%d",&n,&m);
        int from,to;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&from,&to);
            edges[from].push_back(to);
        }
    }
    void initialize()       //初始化
    {
        is_no=num=times=0;
        for(int i=0;i<=n;i++)
        {
            ind[i]=0;
            mark[i]=instack[i]=low[i]=dfn[i]=visited[i]=0;
            edges[i].clear();
            newedge[i].clear();
            Strongly_connected_branch[i]=-1;
        }
    }
    void solve()
    {
        for(int i=1;i<=n;i++)
           if(visited[i]==0)
            {
                visited[i]=1;
                tarjan(i);
            }
         for(int i=1;i<=n;i++)         //重新建图,不在同一个SCB的边留下即可。
        {
            int len=edges[i].size();
           for(int j=0;j<len;j++)
           {
              int v=edges[i][j];
              if(Strongly_connected_branch[v]!=Strongly_connected_branch[i])  //注意用SCB序号作代表元(新节点)来重新建图
              {
                 ind[Strongly_connected_branch[v]]++;
                 newedge[Strongly_connected_branch[i]].push_back(Strongly_connected_branch[v]);
              }
           }
        }
        int is_0ind;
        for(int i=1;i<=num;i++)    //找到入度为0的点,做起点dfs
        {
           if(ind[i]==0)is_0ind=i;
        }
        mark[is_0ind]=1;
        dfs(is_0ind,1);
        if(is_no)printf("Yes
    ");
        else printf("No
    ");
    }
    int main()
    {
        int tcase;
        scanf("%d",&tcase);
       while(tcase--)
       {
           initialize();
           readin();
           solve();
       }
       return 0;
    }
    

  • 相关阅读:
    ARTS习惯(8)
    ARTS习惯(7)
    ARTS习惯(6)
    ARTS习惯(5)
    ARTS习惯(4)
    ARTS习惯(3)
    线程状态
    java线程同步
    数据库视图
    数据库事务
  • 原文地址:https://www.cnblogs.com/yezekun/p/3925813.html
Copyright © 2011-2022 走看看