The Bottom of a Graph
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 9429 | Accepted: 3910 |
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.
Sample Input
3 3 1 3 2 3 3 1 2 1 1 2 0
Sample Output
1 3 2
大神的思路:
<pre class="sio" name="code">定义:点v是汇点须满足 --- 对图中任意点u,若v可以到达u则必有u到v的路径;若v不可以到达u,则u到v的路径可有可无。
题意:在n个点m条边的有向图里面,问有多少个点是汇点。
分析:首先若SCC里面有一个点不是汇点,那么它们全不是汇点,反之也如此。这也就意味着一个SCC里面的点要么全是,要么全不是。在求出SCC并缩点后,任一个编号为A的SCC若存在指向编号为B的SCC的边,那么它里面所有点必不是汇点(因为编号为B的SCC不可能存在指向编号为A的SCC的边)。若编号为A的SCC没有到达其他SCC的路径,那么该SCC里面所有点必是汇点。因此判断的关键在于SCC的出度是否为0.
思路:先用tarjan求出所有SCC,然后缩点后找出所有出度为0的SCC,并用数字存储点,升序排列后输出。
<pre class="cpp" name="code">#include<stdio.h> #include<string.h> #include<algorithm> #include<stack> #include<vector> #define N 5000 #define M 25000000 using namespace std; int a[N]; struct zz { int from; int to; int next; }edge[M]; int head[N],edgenum; int low[N]; int dfn[N],dfs_clock; int sccon[N],scc_cnt; bool instack[N]; vector<int>scc[N]; stack<int>s; int n,m; void add(int u,int v) { zz E={u,v,head[u]}; edge[edgenum]=E; head[u]=edgenum++; } void tarjan(int u,int fa) { int v; low[u]=dfn[u]=++dfs_clock; s.push(u); instack[u]=true; for(int i=head[u];i!=-1;i=edge[i].next) { v=edge[i].to; if(!dfn[v]) { tarjan(v,u); low[u]=min(low[u],low[v]); } else if(instack[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { scc_cnt++; scc[scc_cnt].clear(); while(1) { v=s.top(); s.pop(); instack[v]=false; sccon[v]=scc_cnt; scc[scc_cnt].push_back(v); if(v==u) break; } } } void find(int l,int r) { memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(sccon,0,sizeof(sccon)); memset(instack,false,sizeof(instack)); scc_cnt=dfs_clock=0; for(int i=l;i<=r;i++) if(!dfn[i]) tarjan(i,-1); } int in[N],out[N]; void suodian() { int i; for(i=1;i<=scc_cnt;i++) in[i]=out[i]=0; for(i=0;i<edgenum;i++) { int u=sccon[edge[i].from]; int v=sccon[edge[i].to]; if(u!=v) { in[v]++; out[u]++; } } } void solve() { find(1,n); suodian(); int i,j,k=0; for(i=1;i<=scc_cnt;i++) { if(out[i]==0) { for(j=0;j<scc[i].size();j++) a[k++]=scc[i][j]; } } sort(a,a+k); printf("%d",a[0]); for(i=1;i<k;i++) printf(" %d",a[i]); printf("\n"); } int main() { int x,y; while(scanf("%d",&n),n) { scanf("%d",&m); memset(head,-1,sizeof(head)); edgenum=0; while(m--) { scanf("%d%d",&x,&y); add(x,y); } solve(); } return 0; }
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stack>
#include<vector>
#define N 5000
#define M 25000000
using namespace std;
int a[N];
struct zz
{
int from;
int to;
int next;
}edge[M];
int head[N],edgenum;
int low[N];
int dfn[N],dfs_clock;
int sccon[N],scc_cnt;
bool instack[N];
vector<int>scc[N];
stack<int>s;
int n,m;
void add(int u,int v)
{
zz E={u,v,head[u]};
edge[edgenum]=E;
head[u]=edgenum++;
}
void tarjan(int u,int fa)
{
int v;
low[u]=dfn[u]=++dfs_clock;
s.push(u);
instack[u]=true;
for(int i=head[u];i!=-1;i=edge[i].next)
{
v=edge[i].to;
if(!dfn[v])
{
tarjan(v,u);
low[u]=min(low[u],low[v]);
}
else if(instack[v])
low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
scc_cnt++;
scc[scc_cnt].clear();
while(1)
{
v=s.top();
s.pop();
instack[v]=false;
sccon[v]=scc_cnt;
scc[scc_cnt].push_back(v);
if(v==u)
break;
}
}
}
void find(int l,int r)
{
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(sccon,0,sizeof(sccon));
memset(instack,false,sizeof(instack));
scc_cnt=dfs_clock=0;
for(int i=l;i<=r;i++)
if(!dfn[i])
tarjan(i,-1);
}
int in[N],out[N];
void suodian()
{
int i;
for(i=1;i<=scc_cnt;i++)
in[i]=out[i]=0;
for(i=0;i<edgenum;i++)
{
int u=sccon[edge[i].from];
int v=sccon[edge[i].to];
if(u!=v)
{
in[v]++;
out[u]++;
}
}
}
void solve()
{
find(1,n);
suodian();
int i,j,k=0;
for(i=1;i<=scc_cnt;i++)
{
if(out[i]==0)
{
for(j=0;j<scc[i].size();j++)
a[k++]=scc[i][j];
}
}
sort(a,a+k);
printf("%d",a[0]);
for(i=1;i<k;i++)
printf(" %d",a[i]);
printf("\n");
}
int main()
{
int x,y;
while(scanf("%d",&n),n)
{
scanf("%d",&m);
memset(head,-1,sizeof(head));
edgenum=0;
while(m--)
{
scanf("%d%d",&x,&y);
add(x,y);
}
solve();
}
return 0;
}