思路:
Tarjan+缩点。
首先跑一遍Tarjan,统计结点个数大于$1$的连通分量个数。然后寻找统计结点个数大于$1$且出度为$0$的连通分量,若只存在一个这样的连通分量,输出其点集即可。
1 #include<stack> 2 #include<cstdio> 3 #include<cctype> 4 #include<vector> 5 inline int getint() { 6 char ch; 7 while(!isdigit(ch=getchar())); 8 int x=ch^‘0‘; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^‘0‘); 10 return x; 11 } 12 const int V=100001; 13 std::vector<int> e[V]; 14 inline void add_edge(const int u,const int v) { 15 e[u].push_back(v); 16 } 17 int dfn[V],low[V],scc[V],id=0,cnt=0; 18 bool ins[V]; 19 std::stack<int> s; 20 void Tarjan(const int x) { 21 low[x]=dfn[x]=++cnt; 22 s.push(x); 23 ins[x]=true; 24 for(unsigned i=0;i<e[x].size();i++) { 25 int &y=e[x][i]; 26 if(!dfn[y]) { 27 Tarjan(y); 28 low[x]=std::min(low[x],low[y]); 29 } 30 else if(ins[y]) { 31 low[x]=std::min(low[x],dfn[y]); 32 } 33 } 34 if(dfn[x]==low[x]) { 35 id++; 36 int y=x; 37 do { 38 y=s.top(); 39 s.pop(); 40 ins[y]=false; 41 scc[y]=id; 42 } while(y!=x); 43 } 44 } 45 int out[V]={0},size[V]={0}; 46 int main() { 47 int n=getint(); 48 for(int m=getint();m;m--) { 49 int u=getint(),v=getint(); 50 add_edge(u,v); 51 } 52 for(int i=1;i<=n;i++) { 53 if(!dfn[i]) Tarjan(i); 54 } 55 for(int x=1;x<=n;x++) { 56 size[scc[x]]++; 57 for(unsigned i=0;i<e[x].size();i++) { 58 int &y=e[x][i]; 59 if(scc[x]!=scc[y]) out[scc[x]]++; 60 } 61 } 62 int ans1=0,cnt=0; 63 std::vector<int> ans; 64 for(int i=1;i<=id;i++) { 65 if(size[i]>1) ans1++; 66 if(out[i]) continue; 67 if(size[i]==1) continue; 68 cnt++; 69 for(int j=1;j<=n;j++) { 70 if(scc[j]==i) ans.push_back(j); 71 } 72 } 73 printf("%d\n",ans1); 74 if(cnt==1) { 75 for(unsigned i=0;i<ans.size();i++) { 76 printf("%d ",ans[i]); 77 } 78 } 79 else puts("-1"); 80 return 0; 81 }
时间: 2024-10-14 21:46:00