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 G and 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.
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 G and 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.
![](http://writeblog.csdn.net/images/2553_1.jpg)
Sample Input
3 3 1 3 2 3 3 1 2 1 1 2 0
Sample Output
1 3 2
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=100000; struct edge { int t,w;//u->t=w; int next; }; int V,E;//点数(从1开始),边数 int p[maxn],pf[maxn];//邻接表原图,逆图 edge G[maxn],Gf[maxn];//邻接表原图,逆图 int l,lf; void init() { memset(p,-1,sizeof(p)); memset(pf,-1,sizeof(pf)); l=lf=0; } void addedge(int u,int t,int w,int l) { G[l].w=w; G[l].t=t; G[l].next=p[u]; p[u]=l; } void addedgef(int u,int t,int w,int l) { Gf[l].w=w; Gf[l].t=t; Gf[l].next=pf[u]; pf[u]=l; } ///Kosaraju算法,返回为强连通分量个数 bool flag[maxn]; //访问标志数组 int belg[maxn]; //存储强连通分量,其中belg[i]表示顶点i属于第belg[i]个强连通分量 int numb[maxn]; //结束时间(出栈顺序)标记,其中numb[i]表示离开时间为i的顶点 //用于第一次深搜,求得numb[1..n]的值 void VisitOne(int cur, int &sig) { flag[cur] = true; for (int i=p[cur];i!=-1;i=G[i].next) { if (!flag[G[i].t]) { VisitOne(G[i].t,sig); } } numb[++sig] = cur; } //用于第二次深搜,求得belg[1..n]的值 void VisitTwo(int cur, int sig) { flag[cur] = true; belg[cur] = sig; for (int i=pf[cur];i!=-1;i=Gf[i].next) { if (!flag[Gf[i].t]) { VisitTwo(Gf[i].t,sig); } } } //Kosaraju算法,返回为强连通分量个数 int Kosaraju_StronglyConnectedComponent() { int i, sig; //第一次深搜 memset(flag,0,sizeof(flag)); for ( sig=0,i=1; i<=V; ++i ) { if ( false==flag[i] ) { VisitOne(i,sig); } } //第二次深搜 memset(flag,0,sizeof(flag)); for ( sig=0,i=V; i>0; --i ) { if ( false==flag[numb[i]] ) { VisitTwo(numb[i],++sig); } } return sig; } //缩点 int n;//缩点后的点个数1~n int g[maxn]; edge eg[maxn];//邻接表 int re; int cont[maxn]; int out[maxn]; void dinit(int sig) { memset(g,-1,sizeof(g)); n=sig; re=0; memset(out,0,sizeof(out)); memset(cont,0,sizeof(cont));//1~n 第sig块强联通分量中的点数 } void addedge0(int u,int t,int w,int l) { eg[l].w=w; eg[l].t=t; eg[l].next=g[u]; g[u]=l; } int main() { while(scanf("%d",&V)==1&&V) { scanf("%d",&E); init(); for(int i=0;i<E;i++) { int u,t,w=1;scanf("%d%d",&u,&t); addedge(u,t,w,l++); addedgef(t,u,w,lf++); } int ans=Kosaraju_StronglyConnectedComponent(); //printf("%d/n",ans); ///缩点 dinit(ans); for(int i=1;i<=V;i++)//构图 { for(int j=p[i];j!=-1;j=G[j].next) { int st=belg[i],ed=belg[G[j].t]; if(st!=ed) { addedge0(st,ed,1,re++); } } } //计算每块强联通分量中的点个数 for(int i=1;i<=V;i++) { cont[belg[i]]++; } //计算DAG图中各点的出度 for(int i=1;i<=n;i++) { for(int j=g[i];j!=-1;j=eg[j].next) { out[i]++; } } /* 先求图中的强连通分支,缩点,如果一个连通分支的出度为0,则这个连通分支中的所 有点都满足条件,输出即可(如果一个连通分支中有一个点可以到达该连通分支以外的 点,则该连通分支中的所有点都不满足条件) */ int f=0; for(int i=1;i<=V;i++) { if(out[belg[i]]==0) { if(f==0) { printf("%d",i);f=1; } else printf(" %d",i); } }printf("/n"); } return 0; }