我们将使用图论中的以下(标准)定义。设V是一个非空的有限集合,其元素称为顶点(或节点)。设E是笛卡尔积V×V的子集,其元素称为边。则G=(V,E)称为有向图。
设n为正整数,设p=(e1,…,en)为边ei∈E的长度为n的序列,使得顶点序列(v1,…,vn+1)的ei=(vi,vi+1)。那么p称为G中从顶点v1到顶点vn+1的路径,我们说vn+1可从v1到达,写为(v1→vn+1)。
这里有一些新的定义。图G=(v,E)中的节点v称为汇,如果对于G中从v可到达的每个节点w,v也可从w到达。图的底部是所有汇节点的子集,即,底部(G)={v∈v|∀w∈v:(v→w)中⇒(宽)→v) }。你必须计算某些图的底部。
输入
输入包含多个测试用例,每个测试用例对应于一个有向图G。每个测试用例以一个整数v开始,表示G=(v,E)的顶点数,其中顶点将由集合v={1,…,v}中的整数标识。您可以假设1<=v<=5000。其后是非负整数e,其后是e对顶点标识符v1,w1,。。。,ve,我们的意思是(vi,wi)∈E。除了这些对指定的边之外,没有其他边。最后一个测试用例后面是一个零。
输出
对于每个测试用例,在单行上输出指定图形的底部。为此,按由单个空格字符分隔的排序顺序打印所有接收节点的编号。如果底部为空,则打印空行。
Sample
Input
3 3
1 3 2 3 3 1
2 1
1 2
0
Outpu
1 3
2
思路
Tarjan算法求有向图的强连通分量,记录点所属的强连通分量序号。遍历每个点的邻接点,若该点和其邻接点所属的强连通分量序号不同,则将该点所属的强连通分量的出度加一。再次遍历每个点,若该点所属的强连通分量的出度为0,则该点为sink点。
AC代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
#define AUTHOR "HEX9CF"
using namespace std;
const int maxn = 100005;
int cnt = 0;
struct Snode {
int to;
int next;
}edge[maxn];
int head[maxn];
// tarjan
int num = 0;
int dfn[maxn], low[maxn];
bool ins[maxn];
stack<int> s;
int scc;
int belong[maxn];
int outDeg[maxn];
void add(int u, int v)
{
edge[cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void print(int n)
{
for (int j = 1; j <= n; j++)
{
cout << j << "-";
for (int i = head[j]; ~i; i = edge[i].next)
{
cout << edge[i].to;
}
cout << endl;
}
}
void init(){
num = 0;
cnt = 0;
scc = 0;
memset(head, -1, sizeof(head));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(belong, -1, sizeof(belong));
memset(outDeg, 0, sizeof(outDeg));
}
void tarjan(int u) {
dfn[u] = low[u] = ++num;
ins[u] = true;
s.push(u);
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to;
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (ins[v])
{
low[u] = min(low[u], dfn[v]);
}
}
// SCC
if(low[u] == dfn[u]) {
int v;
do{
v = s.top();
s.pop();
// cout << v << " ";
belong[v] = scc;
ins[v] = false;
}while(v != u);
scc++;
// cout << endl;
}
}
int main() {
int n, e;
while(cin >> n){
if(!n){
break;
}
init();
cin >> e;
for (int i = 0; i < e; i++)
{
int u, v;
cin >> u >> v;
add(u, v);
}
// print(n);
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)
{
int v = edge[i].to;
if (belong[u] != belong[v])
{
outDeg[belong[u]]++;
}
}
}
int flg = 0;
for (int u = 1; u <= n; u++)
{
if (!outDeg[belong[u]])
{
if (flg)
{
cout << " ";
}
else
{
flg = 1;
}
cout << u;
}
}
cout << endl;
}
return 0;
}