题意:如果v点能够到的点,反过来也能够到v点,则称这个点为sink点,输出所有的sink点
思路:求下强连通分量,出度为0的连通分量里的点都是sink点
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<stack>
using namespace std;
const int maxn = 1e4+5;
int n, m, dfn[maxn], low[maxn], belong[maxn], out[maxn];
int dfs_clock, scc_cnt;
bool is[maxn];
vector<int> g[maxn];
stack<int> s;
void tarjan(int u)
{
dfn[u] = low[u] = ++dfs_clock;
s.push(u);
for(int i = 0; i < g[u].size(); i++)
{
int v = g[u][i];
if(!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(!belong[v])
low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u])
{
scc_cnt++;
while(1)
{
int x = s.top(); s.pop();
belong[x] = scc_cnt;
if(x == u) break;
}
}
}
void find_scc()
{
while(!s.empty()) s.pop();
dfs_clock = scc_cnt = 0;
memset(belong, 0, sizeof(belong));
memset(dfn, 0, sizeof(dfn));
for(int i = 1; i <= n; i++)
if(!dfn[i])
tarjan(i);
}
void solve()
{
memset(out, 0, sizeof(out));
memset(is, 0, sizeof(is));
for(int u = 1; u <= n; u++)
for(int i = 0; i < g[u].size(); i++)
{
int v = g[u][i];
if(belong[u] != belong[v])
out[belong[u]]++;
}
for(int i = 1; i <= scc_cnt; i++)
if(!out[i])
is[i] = 1;
int lead = 0;
for(int i = 1; i <= n; i++)
if(is[belong[i]])
{
if(lead++) printf(" ");
printf("%d", i);
}
puts("");
}
int main(void)
{
while(cin >> n && n)
{
scanf("%d", &m);
for(int i = 0; i < maxn; i++)
g[i].clear();
for(int i = 1; i <= m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
}
find_scc();
solve();
}
return 0;
}
The Bottom of a Graph
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 10891 | Accepted: 4491 |
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