pku2553:
题目大意:给定一个n个节点,m条边的有向图。对某个节点v,如果从它能到达的节点w,那么从w也能到达v;这样的节点称为sink。求出图中所有的sink并排序输出。
解法:很明显和强连通分量有关,缩点后形成一张DAG图,所求既是出度为0的缩点对应的原始点。
#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;
}