zoukankan      html  css  js  c++  java
  • The Bottom of a Graph-POJ2553强连通

    The Bottom of a Graph


    Time Limit: 3000MS Memory Limit: 65536K
    Total Submissions: 9759 Accepted: 4053

    Description
    We will use the following (standard) definitions from graph theory. Let V be a nonempty and finite set, its elements being called vertices (or nodes). Let E be a subset of the Cartesian product V×V, its elements being called edges. Then G=(V,E) is called a directed graph.

    Let n be a positive integer, and let p=(e1,…,en) be a sequence of length n of edges ei∈E such that ei=(vi,vi+1) for a sequence of vertices (v1,…,vn+1). Then p is called a path from vertex v1 to vertex vn+1 in G and we say that vn+1 is reachable from v1, writing (v1→vn+1).

    Here are some new definitions. A node v in a graph G=(V,E) is called a sink, if for every node w in G that is reachable from v, v is also reachable from w. The bottom of a graph is the subset of all nodes that are sinks, i.e., bottom(G)={v∈V|∀w∈V:(v→w)⇒(w→v)}. You have to calculate the bottom of certain graphs.

    Input

    The input contains several test cases, each of which corresponds to a directed graph G. Each test case starts with an integer number v, denoting the number of vertices of G=(V,E), where the vertices will be identified by the integer numbers in the set V={1,…,v}. You may assume that 1<=v<=5000. That is followed by a non-negative integer e and, thereafter, e pairs of vertex identifiers v1,w1,…,ve,we with the meaning that (vi,wi)∈E. There are no edges other than specified by these pairs. The last test case is followed by a zero.

    这里写图片描述

    Output

    For each test case output the bottom of the specified graph on a single line. To this end, print the numbers of all nodes that are sinks in sorted order separated by a single space character. If the bottom is empty, print an empty line.

    Sample Input

    3 3
    1 3 2 3 3 1
    2 1
    1 2
    0

    Sample Output

    1 3
    2

    Source

    Ulm Local 2003

    题意:使用的图论的方式说明了一个新的定义,汇点的定义,v是图中的一个顶点,对于图中的每一个顶点w,如果v可达w并且w也可达v,ze称v为汇点。图的底部为图的子集,子集中的所有的点都是汇点,求图的底部。
    思路:如果图的底部都是汇点,则说明底部中的任意两点都互相可达,则底部为强连通分量,并且这个集合不与外部相连即从这个集合不能到达其他的集合,所以任务就变成求图的强连通分量并且出度为零

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <cstdlib>
    #include <queue>
    #include <stack>
    #include <set>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    const int Max = 5010;
    
    typedef struct node
    {
        int v;
    
        int next;
    }Line;
    
    Line Li[Max*1000];
    
    int Head[Max],top;
    
    int dfn[Max],low[Max],pre[Max],dep;
    
    vector<int>G[Max];
    
    int a[Max],num,Du[Max],Num;
    
    bool vis[Max];
    
    stack <int> S;
    
    int n,m;
    
    void AddEdge(int u,int v)
    {
        Li[top].v = v; Li[top].next = Head[u];
    
        Head[u] = top++;
    }
    
    void Tarjan(int u) // Tarjan求强连通分量
    {
    
        dfn[u]=low[u]=dep++;
    
        S.push(u);
    
        for(int i=Head[u];i!=-1;i=Li[i].next)
        {
            if(dfn[Li[i].v]==-1)
            {
                Tarjan(Li[i].v);
    
                low[u] = min(low[u],low[Li[i].v]);
            }
            else
            {
                low[u]=min(low[u],dfn[Li[i].v]);
            }
        }
    
        if(low[u]==dfn[u])// 如果low[u]=dfn[u],则说明是强连通分的根节点
        {
            while(!S.empty())
            {
                int v = S.top();
    
                S.pop();
    
                G[Num].push_back(v);
    
                pre[v]=Num;
    
                if(v==u)
                {
                    break;
                }
            }
    
            Num++;
        }
    }
    
    int main()
    {
        int u, v;
    
        while(~scanf("%d",&n)&&n)
        {
            scanf("%d",&m);
    
            top = 0;
    
            memset(Head,-1,sizeof(Head));
    
            for(int i=0;i<m;i++)
            {
                scanf("%d %d",&u,&v);
    
                AddEdge(u,v);
            }
    
            memset(dfn,-1,sizeof(dfn));
    
    
            for(int i=0;i<=n;i++)
            {
                G[i].clear();
            }
    
            dep = 0;Num = 0;
    
            for(int i=1;i<=n;i++)
            {
                if(dfn[i]==-1)
                {
                    Tarjan(i);
                }
            }
    
            memset(Du,0,sizeof(Du));
    
            for(int i=0;i<Num;i++)
            {
                memset(vis,false,sizeof(vis));
    
                for(int k=0;k<G[i].size();k++)
                {
                    for(int j=Head[G[i][k]];j!=-1;j = Li[j].next)
                    {
                        if(i != pre[Li[j].v]&&!vis[pre[Li[j].v]])//集合间度的计算
                        {
                            vis[pre[Li[j].v]]=true;
    
                            Du[i]++;
                        }
                    }
                }
            }
    
            num = 0;
    
            for(int i=0;i<Num;i++)
            {
                if(Du[i]==0)
                {
                    for(int j=0;j<G[i].size();j++)
                    {
                        a[num++]=G[i][j];
                    }
                }
            }
            sort(a,a+num);// 排序输出
    
            for(int i=0;i<num;i++)
            {
                if(i)
                {
                    printf(" ");
                }
                printf("%d",a[i]);
            }
            printf("
    ");
    
        }
    
        return 0;
    }
  • 相关阅读:
    变量的创建和初始化
    HDU 1114 Piggy-Bank (dp)
    HDU 1421 搬寝室 (dp)
    HDU 2059 龟兔赛跑 (dp)
    HDU 2571 命运 (dp)
    HDU 1574 RP问题 (dp)
    HDU 2577 How to Type (字符串处理)
    HDU 1422 重温世界杯 (dp)
    HDU 2191 珍惜现在,感恩生活 (dp)
    HH实习 acm算法部 1689
  • 原文地址:https://www.cnblogs.com/juechen/p/5255889.html
Copyright © 2011-2022 走看看