http://poj.org/problem?id=2762
题目给出n个点m条单向边,问是否存在取任意两点x,y,使得可以x->y或y->x,其实就是求弱连通分量....
方法:缩点+拓扑。因为环内各点肯定可以任意到达,缩完点后就可能变成树或森林,当树是一条链的时候才存在弱连通分量,拓扑一下就ok...
一开始看不到The cave has n rooms, andone-way corridors connecting some rooms.单向边!!!以为是无向边,并且每条边只能走一次,如果这样的话,就跟zoj3583一样,变了求简单路径
#define N 1004 int n; bool g[N][N]; bool vis[N]; bool inStack[N]; int out[N],in[N]; int belong[N]; int low[N],dfn[N]; stack<int> st; int t;//the number of 强连通分量 int step; int min(int a,int b){ return a>b?b:a; } int max(int a,int b){ return a>b?a:b; } void init(){ t = 0; memset(g,0,sizeof(g)); memset(vis,0,sizeof(vis)); memset(belong,0,sizeof(belong)); memset(inStack,0,sizeof(inStack)); while(!st.empty())st.pop(); } void tarjan(int u){ int i,j,k; step++; low[u]=step; dfn[u]=step; vis[u]=1; inStack[u]=1; st.push(u); for(i=1;i<=n;i++) { if(g[u][i]) { if(!vis[i]) { tarjan(i); low[u]=min(low[u],low[i]); } else if(inStack[i]) low[u]=min(low[u],dfn[i]); } } if(low[u]==dfn[u]) { t++; while(1) { int a=st.top(); st.pop(); belong[a]=t; inStack[a]=0; if(a==u)break; } } } int du[N]; int gg[N][N]; bool vv[N]; bool topo(){ int i,j; queue<int> qq; for(i=1;i<=t;i++){ vv[i] = 0; if(!du[i]){ qq.push(i); vv[i] = 1; } } int sz = qq.size(); if(sz!=1)return false; while(!qq.empty()){ int u = qq.front(); qq.pop(); int cnt = 0; for(i=1;i<=t;i++){ if(!vv[i] && gg[u][i]){ du[i]--; if(du[i]==0){ cnt++; qq.push(i); vv[i] = 1; }if(cnt>=2)return false; } } } return true; } int main(){ int ca; scanf("%d",&ca); while(ca--){ int m; scanf("%d%d",&n,&m); int i,j; init(); while(m--){ int x,y; scanf("%d%d",&x,&y); g[x][y] = 1; } for(i=1;i<=n;i++){ if(!vis[i])tarjan(i); } for(i=0;i<=t;i++)du[i] = 0; memset(gg,0,sizeof(gg)); for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ if(g[i][j]){ int a = belong[i]; int b = belong[j]; if(a!=b){ du[b]++; gg[a][b] = 1; } } } } if(topo())puts("Yes"); else puts("No"); } return 0; }