POJ 2553--The Bottom of a Graph【scc缩点构图 && 求出度为0的scc && 输出scc中的点】

原创 2015年08月20日 09:20:38

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

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

解析偷偷粘的阿宇的博客

定义:点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,并用数字存储点,升序排列后输出。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define maxn 5000
#define maxm 5000 * 5000
using namespace std;
int n, m;
struct node{
    int u, v, next;
};

node edge[maxm];

int head[maxn], cnt;
int low[maxn], dfn[maxn];
int dfs_clock;
int Stack[maxn], top;
bool Instack[maxn];
int Belong[maxn];
int scc_clock;
int in[maxn], out[maxn];
vector<int>scc[maxn];
int num[maxn];

void init(){
    cnt = 0;
    memset(head, -1, sizeof(head));
}

void addedge(int u, int v){
    edge[cnt] = {u, v, head[u]};
    head[u] = cnt++;
}

void getmap(){
    while(m--){
        int a, b;
        scanf("%d%d", &a, &b);
        addedge(a, b);
    }
}

void Tarjan(int u, int per){
    int v;
    low[u] = dfn[u] = ++dfs_clock;
    Stack[top++] = u;
    Instack[u] = true;
    for(int i = head[u]; i != -1; i = edge[i].next){
        int v = edge[i].v;
        if(!dfn[v]){
            Tarjan(v, u);
            low[u] = min(low[u], low[v]);
        }
        else if(Instack[v])
            low[u] = min(low[u], dfn[v]);
    }
    if(dfn[u] == low[u]){
        scc_clock++;
        scc[scc_clock].clear();
        do{
            v = Stack[--top];
            Instack[v] = false;
            Belong[v] = scc_clock;
            scc[scc_clock].push_back(v);
        }
        while( v != u);
    }
}

void suodian(){
    for(int i = 1; i <= scc_clock; ++i){
        out[i] = 0;
    }
    for(int i = 0; i < cnt; ++i){
        int u = Belong[edge[i].u];
        int v = Belong[edge[i].v];
        if(u != v)
            out[u]++;
    }
}

void find(){
    memset(low, 0, sizeof(low));
    memset(dfn, 0, sizeof(dfn));
    memset(Belong, 0, sizeof(Belong));
    memset(Stack, 0, sizeof(Stack));
    memset(Instack, false, sizeof(false));
    dfs_clock = scc_clock = top = 0;
    for(int i = 1; i <= n ; ++i){
        if(!dfn[i])
            Tarjan(i, i);
    }
}

void solve(){
    int k = 0;
    for(int i = 1; i <= scc_clock; ++i){
        if(out[i] == 0){
            for(int j = 0; j < scc[i].size(); ++j)
                num[k++] = scc[i][j];
        }
    }
    sort(num, num + k);
    for(int i = 0; i < k; ++i){
        if(!i)
            printf("%d", num[i]);
        else
            printf(" %d", num[i]);
    }
    printf("\n");
}

int main (){
    while(scanf("%d", &n), n){
        scanf("%d", &m);
        init();
        getmap();
        find();
        suodian();
        solve();
    }
    return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

poj2767,单向连通图判定,缩点+重新建图+新图DFS

/*该题被博客里标记为中等题,30分钟内1A,掌握了算法就简单了,单向连通图判定,单向连通图缩点 后必然唯一存在出度为0的点和入度为0的点,并且从入度为0的点出发,可以遍历所有点后到达出度为0点 (一...
  • u011498819
  • u011498819
  • 2014年02月09日 20:08
  • 788

朱刘算法 , 以UVa11183为例

本文参考借鉴了其他文章 , 但原作者以无从考证了 , 表示感谢 我对朱刘算法的认识不够深入 , 但希望我的文章能给初学者一些帮助 , 因为很多网友的文章淡化了初学者不理解的细节 , 希望这篇文章能够帮...
  • Fuxey
  • Fuxey
  • 2015年10月12日 22:36
  • 944

hdu 4635 Strongly connected 【图论-强连通分量-缩点-完全图】

Strongly connected Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Jav...
  • xingdragon
  • xingdragon
  • 2017年04月13日 18:19
  • 310

HDU 5458 Stability(LCA倍增算法, 并查集缩点(一般都是连通缩点))

转载地址:http://www.cnblogs.com/oyking/p/4821902.html 题目大意:给一个N个点M条边的无向图,有Q个询问:1、删掉a、b之间所存在的边;2、询问有多少条边...
  • weishengmingerfendou
  • weishengmingerfendou
  • 2015年09月23日 12:32
  • 432

强连通分量(SCC)详解

说到以Tarjan命名的算法,我们经常提到的有3个,其中就包括本文所介绍的求强连通分量的Tarjan算法。而提出此算法的普林斯顿大学的Robert E Tarjan教授也是1986年的图灵奖获得者(具...
  • L123012013048
  • L123012013048
  • 2015年09月08日 16:05
  • 796

UVA 10972(边双连通分量)

题目链接:UVA 10972解题思路: 这题的题意很简单,就是给一个无向图,然后要求我们把所有的边都变成有向边,然后再另外添加一些有向边,最终用最少的边把有向图变成强连通的。一眼看过去是懵比的,然而...
  • fuyukai
  • fuyukai
  • 2016年05月03日 23:19
  • 556

tarjan模板(缩点,求有向图强连通分量)

整理出了这个tarjan模板,具体数组的功能代码都有注释。 const int N=100010; struct data { int to,next; } tu[N*2]; int head...
  • martinue
  • martinue
  • 2016年05月04日 15:53
  • 1520

kosaraju算法-求解有向图SCC

算法流程: 1)制作反图 2)任选一个没有标记的节点,正向dfs,在回溯之前打上时间标记(叶子的标记在前) 3)重复2直到所有点被标记 4)选择时间标记最大,且没有被加入连通块的点,连通块计数器加1,...
  • slowlight93
  • slowlight93
  • 2015年02月05日 16:55
  • 440

强连通分量(SCC)Kosaraju算法学习笔记

一、深度优先生成树 在对无向图或有向图G进行从顶点v出发的深度优先搜索时,由v引向未被访问(标记)的顶点的边,构成以v为根的一棵树,这棵树被称为深度优先生成树(DFST)。 始点v称为树根、树上的每...
  • u014679804
  • u014679804
  • 2015年06月25日 18:06
  • 1257

HEVC及其参考测试软件的发展历程

背景: HEVC是由ITU-T视频编码专家组和ISO/IEC运动图像专家组联合制定的视频编码标准,并开发了参考软件HM (HEVC Test Model)。 专家组成立了Joint Collabo...
  • lin453701006
  • lin453701006
  • 2016年10月17日 15:37
  • 925
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:POJ 2553--The Bottom of a Graph【scc缩点构图 && 求出度为0的scc && 输出scc中的点】
举报原因:
原因补充:

(最多只允许输入30个字)