• POJ2553 汇点个数(强连通分量


    The Bottom of a Graph
    Time Limit: 3000MS   Memory Limit: 65536K
    Total Submissions: 12070   Accepted: 4971

    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 vv 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

    定义:点v是汇点须满足 --- 对图中任意点u,若v可以到达u则必有u到v的路径;若v不可以到达u,则u到v的路径可有可无。

    题意:在n个点m条边的有向图里面,问有多少个点是汇点。

    分析:若SCC里有一点不是汇点,那么它们全不是,反之也如此。所以一个SCC里面的点要么全是,要么全不是。在求出SCC并缩点后,任一个编号为A的SCC若存在指向编号为B的SCC的边,那么其所有点必不是汇点(因为编号为B的SCC不可能存在指向编号为A的SCC的边)。若编号为A的SCC没有到达其他SCC的路径,那么该SCC里面所有点必是汇点。因此判断的关键在于SCC的出度是否为0.

    思路:先用tarjan求出所有SCC,然后缩点后找出所有出度为0的SCC,并用数字存储点,升序排列后输出。

    代码:

     1 #include"bits/stdc++.h"
     2 
     3 #define db double
     4 #define ll long long
     5 #define vl vector<ll>
     6 #define ci(x) scanf("%d",&x)
     7 #define cd(x) scanf("%lf",&x)
     8 #define cl(x) scanf("%lld",&x)
     9 #define pi(x) printf("%d
    ",x)
    10 #define pd(x) printf("%f
    ",x)
    11 #define pl(x) printf("%lld
    ",x)
    12 #define rep(i, n) for(int i=0;i<n;i++)
    13 using namespace std;
    14 const int N = 1e6 + 5;
    15 const int mod = 1e9 + 7;
    16 const int MOD = 998244353;
    17 const db  PI = acos(-1.0);
    18 const db  eps = 1e-10;
    19 const ll  INF = 0x3fffffffffffffff;
    20 int n,m;
    21 struct P{int to,nxt;}e[N];
    22 int head[N];
    23 bool ins[N];
    24 int beg[N];
    25 int low[N],dfn[N];
    26 int out[N];
    27 stack<int> s;
    28 
    29 int cnt,num,id;
    30 void add(int u,int v){
    31     e[cnt].to=v;
    32     e[cnt].nxt=head[u];
    33     head[u]=cnt++;
    34 }
    35 void tarjan(int u)
    36 {
    37     low[u]=dfn[u]=++id;
    38     ins[u]=1;
    39     s.push(u);
    40     for(int i=head[u];~i;i=e[i].nxt){
    41         int v=e[i].to;
    42         if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
    43         else if(ins[v]) low[u]=min(low[u],dfn[v]);
    44     }
    45     if(low[u]==dfn[u]){
    46         int v;
    47         do{
    48             v=s.top();s.pop();
    49             beg[v]=num;//强连通分量编号
    50             ins[v]=0;
    51         }while(u!=v);
    52         num++;
    53     }
    54 }
    55 int main(){
    56     while (scanf("%d%d",&n,&m)==2&&n){
    57         memset(head,-1, sizeof(head));
    58         memset(low,0, sizeof(low));
    59         memset(dfn,0, sizeof(dfn));
    60         memset(ins,0, sizeof(ins));
    61         memset(out,0, sizeof(out));
    62         cnt=num=id=0;
    63         for(int i=0;i<m;i++){
    64             int x,y;
    65             ci(x),ci(y);
    66             add(x,y);
    67         }
    68         for(int i=1;i<=n;i++)
    69             if(!dfn[i]) tarjan(i);
    70         for(int i=1;i<=n;i++){
    71             for(int j=head[i];~j;j=e[j].nxt){
    72                 int v=e[j].to;
    73                 if(beg[i]!=beg[v]) out[beg[i]]++;
    74             }
    75         }
    76         bool ok=1;
    77         for(int i=1;i<=n;i++){
    78             if(!out[beg[i]]){//所在强连通分量出度为0
    79                 if(ok) printf("%d",i),ok=0;
    80                 else printf(" %d",i);
    81             }
    82         }
    83         puts("");
    84     }
    85     return 0;
    86 }
  • 相关阅读:
    Java——通过Java代码启动批处理文件
    成功解决错误1130 Host xxx is not allowed to connect to this MySQL server
    SQL全文索引的作用(转)
    查找不重复记录
    全文索引原理和一个完整的SQL SERVER数据库全文索引的示例(转)
    C# 参考:令人惊喜的泛型委托 Predicate/Func/Action
    moss 外网访问设置
    SQL2000和SQL2005的行转列处理方法
    海量数据库查询
    MSSQL 查询优化二(转)
  • 原文地址:https://www.cnblogs.com/mj-liylho/p/9545668.html
Copyright © 2020-2023  润新知