您的位置:首页 > 运维架构

POJ 2186 Popular Cows(强连通分量)

2014-08-15 16:10 477 查看

题目大意:

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

补充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 10005
using 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息