这个题的题意真是醉了 一个点是sink不是说他和任一点互相可达,而是如果他能到达一个点的情况下,那个点必须能够到达他 = =。这样的话就是强连通缩点之后,出度为零的点及其强连通分量中的所有点都是sink。
#include <stack>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 5010;
const int M = 250010;
stack <int> S;
int n, m;
int ans, id[N];
int tot, head[N], out[N];
int dfs_clock, point, pre[N], low[N], vis[N], belong[N];
struct edge{
int v, next;
}node[M];
void init(){
tot = point = dfs_clock = ans = 0;
for(int i=1; i<=n; i++){
head[i] = -1;
pre[i] = 0;
vis[i] = 0;
out[i] = 0;
}
while(!S.empty()) S.pop();
}
void addedge(int u, int v){
node[tot].v = v;
node[tot].next = head[u];
head[u] = tot++;
}
void Tarjan(int u){
pre[u] = low[u] = ++dfs_clock;
vis[u] = 1;
S.push(u);
for(int i=head[u]; i!=-1; i=node[i].next){
int v = node[i].v;
if(!pre[v]){
Tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(vis[v] && pre[v] < low[u])
low[u] = pre[v];
}
if(pre[u] == low[u]){
point++;
int x;
do{
x = S.top();
vis[x] = 0;
belong[x] = point;
S.pop();
}while(u != x);
}
return ;
}
int main(){
while(scanf("%d%d",&n,&m) == 2 && n){
init();
for(int i=0; i<m; i++){
int u, v;
scanf("%d%d",&u,&v);
addedge(u, v);
}
for(int i=1; i<=n; i++)
if(!pre[i]) Tarjan(i);
if(point == 1){
printf("1");
for(int i=2; i<=n; i++)
printf(" %d",i);
puts("");
continue;
}
for(int u=1; u<=n; u++){
for(int i=head[u]; i!=-1; i=node[i].next){
int v = node[i].v;
if(belong[u] != belong[v]){
out[belong[u]]++;
}
}
}
bool flag = true;
for(int i=1; i<=n; i++){
if(out[belong[i]]) continue;
if(flag){
printf("%d",i);
flag = false;
}
else printf(" %d",i);
}
puts("");
}
return 0;
}