The Bottom of a Graph
http://poj.org/problem?id=2553
Time Limit: 3000MS |
|
Memory Limit: 65536K |
|
|
|
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
Gand 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
v,
v 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(对于任一点w,若v可达w,则w可达v)?
注意理解题意即可(只有理解了,才能看懂样例...)
满足题意的v点有两种情况:
①对于任一点w,v可达w,且w可达v,即v、w互相可达,满足该情况的点在同一个强连通分量中(且该强连通分量不与其他点连通)
②对于任一点w,v均不可达w,满足该情况的点是出度为0的点
所以可以先求出所有的强连通分量,并缩点,则只剩下情况②,则所有出度为0的缩点都满足题意,即缩点中的点都满足题意
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN=5005;
int n,m,num,cnt,top,tot;
int stak[MAXN],ans[MAXN];
int low[MAXN],dfn[MAXN],color[MAXN],outdeg[MAXN];//biocks[i]表示删掉i点后,能形成的连通块数
vector<int> g[MAXN];
bool isIn[MAXN];
void Tarjan(int u) {
stak[++top]=u;
isIn[u]=true;
dfn[u]=low[u]=++num;
int v;
for(int i=0;i<g[u].size();++i) {
v=g[u][i];
if(dfn[v]==0) {
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(isIn[v]&&dfn[v]<low[u])
low[u]=dfn[v];
}
if(dfn[u]==low[u]) {
++cnt;
do {
v=stak[top--];
isIn[v]=false;
color[v]=cnt;//缩点
} while(v!=u);
}
}
int main() {
int s,e;
while(scanf("%d",&n),n!=0) {
scanf("%d",&m);
for(int i=1;i<=n;++i) {
g[i].clear();
dfn[i]=outdeg[i]=0;
isIn[i]=false;
}
while(m-->0) {
scanf("%d%d",&s,&e);
g[s].push_back(e);
}
tot=cnt=num=top=0;
for(int i=1;i<=n;++i) {
if(dfn[i]==0)
Tarjan(i);
}
for(int i=1;i<=n;++i) {
for(int j=0;j<g[i].size();++j) {
if(color[i]!=color[g[i][j]])
++outdeg[color[i]];//统计各缩点的出度
}
}
for(int i=1;i<=cnt;++i) {
if(outdeg[i]==0) {//若出度为0
for(int j=1;j<=n;++j) {
if(color[j]==i)//若点j缩成点i
ans[tot++]=j;
}
}
}
sort(ans,ans+tot);
if(tot>0) {//本题不会出现无解情况,DAG中必有出度为0的点,否则有环
printf("%d",ans[0]);
for(int i=1;i<tot;++i)
printf(" %d",ans[i]);
}
printf("\n");
}
return 0;
}