图论——强连通分量

pku2553:

题目大意:给定一个n个节点,m条边的有向图。对某个节点v,如果从它能到达的节点w,那么从w也能到达v;这样的节点称为sink。求出图中所有的sink并排序输出。

解法:很明显和强连通分量有关,缩点后形成一张DAG图,所求既是出度为0的缩点对应的原始点。

View Code
#include <iostream>
#include
<cstdio>
#include
<cstring>
#include
<vector>
#include
<algorithm>
usingnamespace std;

constint N =5010;
constint M = N*N;

int n, m, tot, depth, top, ct, stack[N], h[N], d[N], low[N], v[M], nxt[M], index[N];
bool visit[N], instack[N];

vector
<int> ans;

void add(int a, int b)
{
v[tot]
= b;
nxt[tot]
= h[a];
h[a]
= tot++;
}

void dfs(int u)
{
int p, tv, x;
d[u]
= low[u] = depth++;
instack[u]
=true;
stack[
++top] = u;
for(p = h[u]; p !=-1; p = nxt[p])
{
tv
= v[p];
if(d[tv] ==-1)
{
dfs(tv);
low[u]
= min(low[tv], low[u]);
}
elseif(instack[tv])
low[u]
= min(low[u], d[tv]);
}
if(d[u] == low[u])
{
ct
++;
while(top)
{
x
= stack[top--];
instack[x]
=false;
index[x]
= ct;
if(x == u) break;
}
}
}

int main()
{
int i, a, b, j;
while(scanf("%d", &n) != EOF)
{
if(n ==0) break;
memset(h,
-1, sizeof(h));
tot
=0;
scanf(
"%d", &m);
for(i =0; i < m; i++)
{
scanf(
"%d%d", &a, &b);
add(a, b);
}
memset(d,
-1, sizeof(d));
depth
= top = ct =0;
memset(instack,
false, sizeof(instack));
for(i =1; i <= n; i++)
if(d[i] ==-1)
dfs(i);
memset(visit,
true, sizeof(visit));
for(i =1; i <= n; i++)
for(j = h[i]; j !=-1; j = nxt[j])
{
if(index[i] != index[v[j]])
{
visit[index[i]]
=false;
break;
}
}
ans.clear();
for(i =1; i <= n; i++)
if(visit[index[i]])
ans.push_back(i);
sort(ans.begin(), ans.end());
if(ans.size() >0)
{
for(i =0; i < ans.size()-1; i++) printf("%d ", ans[i]);
printf(
"%d\n", ans[i]);
}
else printf("\n");
}
return0;
}

  

你可能感兴趣的:(图论)