POJ2553
SP1799
我們知道單獨一個強連通分量中的所有點是滿足題目要求的
但如果它連出去到了其他點那裡,要麼成為新的強連通分量,要麼失去原有的符合題目要求的性質
所以只需tarjan縮點求出所有強連通分量,再O(E)列舉所有邊,是否會成為連線一個分量與另一個分量的邊——即一條出度——即可
如果一個分量沒有出度,那麼他中間的所有點都是符合題目要求的點
(因為快讀快輸加了太長所以就不貼了)
const int N=5005,M=N*N>>1;
int h[N],en,n,m,dfn[N],out[N],bel[N],low[N],num,cnt;
stack<int> st;
struct edge{int n,u,v;}e[M]; //前向星存邊
inline void add(const int &x,const int &y){e[++en]=(edge){h[x],x,y},h[x]=en;}
inline void tarjan(int x){ //一個tarjan縮點STL棧模板
st.push(x);
dfn[x]=low[x]=++num;
for(int i=h[x];i;i=e[i].n){
int y=e[i].v;
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(!bel[y])
low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x]){
cnt++;
int TOP;
do{
TOP=st.top();
st.pop();
bel[TOP]=cnt;
}while(TOP!=x);
}
}
signed main(){
read(n);
while(n){
en=num=cnt=0;
memset(h,0,sizeof h);
memset(dfn,0,sizeof dfn);
memset(out,0,sizeof out);
memset(bel,0,sizeof bel);
memset(low,0,sizeof low);
read(m);
while(m--){
int x,y;
read(x),read(y);
add(x,y);
}
for(int i=1;i<=n;i++) if(!dfn[i]) //跑縮點
tarjan(i);
for(int i=1,u,v;i<=en;i++){
u=e[i].u,v=e[i].v;
if(bel[u]!=bel[v]) out[bel[u]]++; //判斷每條邊的起點終點是否在同一強連通分量中,如果不是,則起點所在強連通分量出度加1
}
for(int i=1;i<=n;i++) if(!out[bel[i]]) //如果點i所在強連通分量沒有出度則滿足要求,輸出
Write(i,' ');
printf("\n"); //統一換行
read(n);
}
}