问题描述:
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.
输入:
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.
输出:
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.
输入样例:
3 3 1 3 2 3 3 1 2 1 1 2 0
输出样例:
1 3 2
解题思路:
划分出有向图中的各个强连通分量,对其进行缩点,然后找出缩点中出度为0的所有结点,把这个强连通分量包含的元素打印出来。
解题步骤:
Tarjan算法应用:统计有向图中的强连通分量_可惜浅灰的博客-CSDN博客
代码实现:
#include <iostream>
using namespace std;
#include <stack>
#define maxn 5000
int m, n;
int head[maxn], cnt;
int dfn[maxn], low[maxn], num;
stack<int> s;
bool ins[maxn];
int id, belong[maxn];
int out[maxn];
class Edge
{
public:
int to;
int next;
};
Edge edge[maxn << 1];
void InsertEdge(const int& u, const int& v)
{
edge[++cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt;
}
void Tarjan(int u)
{
dfn[u] = low[u] = ++num;
s.push(u);
ins[u] = true;
for (int i = head[u]; i; i = edge[i].next)
{
int v = edge[i].to;
if (!dfn[v])
{
Tarjan(v);
low[u] = min(low[v], low[u]);
}
else if (ins[v])
{
low[u] = min(low[u], dfn[v]);
}
}
if (low[u] == dfn[u])
{
int v = 0;
id++;
do
{
v = s.top();
s.pop();
belong[v] = id;
ins[v] = false;
} while (v != u);
}
}
void Init()
{
memset(head, 0, sizeof(head));
memset(edge, 0, sizeof(edge));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(belong, 0, sizeof(belong));
memset(out, 0, sizeof(out));
cnt = num = id = 0;
}
int main()
{
while (cin >> n && n)
{
cin >> m;
int u, v;
Init();
for (int i = 1; i <= m; i++)
{
cin >> u >> v;
InsertEdge(u, v);
}
for (int i = 1; i <= n; i++)
{
if (!dfn[i])
{
Tarjan(i);
}
}
for (int u = 1; u <= n; u++)
{
for (int i = head[u]; i; i = edge[i].next)
{
v = edge[i].to;
if (belong[u] != belong[v])
{
out[belong[u]]++;
}
}
}
for (int i = 1; i <= n; i++)
{
if (!out[belong[i]])
{
cout << i << " ";
}
}
cout << endl;
}
return 0;
}