POJ 2186 Popular Cows(强连通分量)

来源:互联网 发布:ipad矢量图软件 编辑:程序博客网 时间:2024/05/22 15:10

题目大意:

给定一个有向图,求有多少个顶点是由任何顶点出发都可达的。

补充1:

有向无环图中唯一出度为0的点,一定可以由任何点出发均可达(由于无环,所以从任何点出发往前走,必然终止于一个出度为0的点)

解题思路:

1、求出所有的强连通分量

2、每个强连通分量缩成一点,则形成一个有向无环图DAG

3、DAG上面如果有唯一的出度为0的点,则该点能被所有的点可达。那么该点所代表的连通分量上的所有的原图中的点,都能被原图中的所有点可达,则该连通分量的点数,就是答案

4、DAG上面如果有不止一个出度为0的点,则这些点互相不可达,原问题无解,答案为0

补充2:

Korasaju算法求有向图强连通分支

  begin

    1.深度优先遍历G,算出每个结点u的访问结束时间f[u],起点如何选择无所谓。

    2.深度优先遍历G的转置图GT,选择遍历的起点时,按照结点的访问结束时间从大到小进行。遍历的过程中,一边遍历,一边给结点做分类标记,每找到一个新的起点,分类标记值就加1。

    3.第2步中产生的标记值相同的结点构成深度优先森林中的一棵树,也即一个强连通分量

  end

算法复杂度分析(邻接表)

深度优先搜索的复杂度:O(V+E)

计算GT的复杂度:0或者O(V+E)

总的复杂度:O(V+E)

代码:

#include <cstdio>#include <cstring>#include <cmath>#include <cstdlib>#include <algorithm>#include <vector>#define M 10005using namespace std;struct Cow{    int th;    int starT;    int endT;    int mark;}cow[M];vector <int> adj[M];vector <int> adjT[M];int n, m, t, lable;int vis[M];void dfs1(int v) {   //深度优先遍历G,算出每个结点的结束时间    vis[v] = 1;    for(int i=0; i<adj[v].size(); i++) {        if(vis[adj[v][i]] == 0) {            cow[adj[v][i]].starT = t++;            vis[adj[v][i]] = 1;            dfs1(adj[v][i]);            cow[adj[v][i]].endT = t++;        }    }    return ;}void dfs2(int v) {  //深度优先遍历GT,做分类标记    vis[v] = 1;    for(int i=0; i<adjT[v].size(); i++) {        if(vis[adjT[v][i]] == 0) {            cow[adjT[v][i]].mark = lable;            vis[adjT[v][i]] = 1;            dfs2(adjT[v][i]);        }    }}int cmp1(Cow c1, Cow c2) {    return c1.endT > c2.endT;}int main() {    int i, j, k;    int a, b;    while(~scanf("%d%d", &n, &m)) {        memset(adj, 0, sizeof(adj));        memset(adjT, 0, sizeof(adjT));        for(i=0; i<n; i++) {            adj[i].clear();            adjT[i].clear();        }        for(i=0; i<m; i++) {            scanf("%d%d", &a, &b);            a--; b--;            adj[a].push_back(b);    //原图            adjT[b].push_back(a);   //转置图        }        t = 1;        memset(vis, 0, sizeof(vis));        for(i=0; i<n; i++) {            cow[i].th = i;            if(vis[i] == 0) {                cow[i].starT = t++;                dfs1(i);                cow[i].endT = t++;            }        }        sort(cow, cow+n, cmp1);        lable = 1;        memset(vis, 0, sizeof(vis));        for(i=0; i<n; i++) {            if(vis[cow[i].th] == 0) {                cow[cow[i].th].mark = lable;                dfs2(cow[i].th);                lable ++;            }        }        int tmpA[M];        memset(tmpA, 0, sizeof(tmpA));        for(i=0; i<n; i++) {                  //标记缩点后的点的出度情况            for(j=0; j<adj[cow[i].th].size(); j++) {                if(cow[cow[i].th].mark != cow[adj[cow[i].th][j]].mark) {                    tmpA[cow[cow[i].th].mark] = 1;                }            }        }        int ans = 0;        int ansN = 0;   //统计缩点后的优先无环图的入度为0的点的个数        for(i=1; i<lable; i++) {            if(tmpA[i] == 0) {                ans = i;                ansN ++;            }        }        if(ansN > 1) {            printf("0\n");            continue;        }        int res = 0;        for(i=0; i<n; i++) {            if(cow[i].mark == ans) {                res ++;            }        }        printf("%d\n", res);    }    return 0;}


0 0
原创粉丝点击