[单连通] poj 2762

来源:互联网 发布:篮球教学视频软件 编辑:程序博客网 时间:2024/05/16 07:40
/**[单连通] poj 2762判断一个图是否是单连通的。强连通缩点+拓扑排序,满足条件是拓扑排序后的序列相邻点间要有边,即存在有向边(topo[i],topo[i+1])。*/#include <stdio.h>#include <string.h>#include <vector>#include <algorithm>using namespace std;#define N 1024vector<int> g[N];int n,m,low[N],ord[N],id[N],sp,scnt,stk[N],tim;int in[N],topo[N],tp;vector<int> gg[N];bool mat[N][N];void dfs(int u){int minc = low[u] = ord[u] = ++tim;stk[sp++] = u;for(int i = 0; i < g[u].size(); ++i){int v = g[u][i];if(ord[v] == 0)dfs(v);minc = min(minc,low[v]);}if(minc < low[u]){low[u] = minc;return ;}int t;do{id[t = stk[--sp] ] = scnt;low[t] = n + 1;}while(t != u);++scnt;}int main(){int t,i,j,k;scanf("%d",&t);while(t--){memset(ord,0,sizeof(ord));memset(g,0,sizeof(g));memset(id,-1,sizeof(id));scnt = sp = tim = 0;scanf("%d%d",&n,&m);while(m--){scanf("%d%d",&i,&j);if(i != j)g[i].push_back(j);}if(n < 2){puts("Yes");continue;}for(i = 1; i <= n; ++i)if(!ord[i])dfs(i);memset(gg,0,sizeof(gg));memset(mat,0,sizeof(mat));for(i = 1; i <= n; ++i){for(j = 0; j < g[i].size(); ++j){k = g[i][j];if(id[i] != id[k]){gg[id[i]].push_back(id[k]);in[id[k]] ++;mat[id[i]][id[k]] = 1;}}}if(scnt == 1){puts("Yes");continue;}sp = tp = 0;for(i = 0; i < scnt; ++i)if(in[i] == 0)topo[tp++] = stk[sp++] = i;while(sp){k = stk[--sp];for(i = 0; i < gg[k].size(); ++i){j = gg[k][i];if(--in[j] == 0)topo[tp++] = stk[sp++] = j;}}if(tp != scnt){puts("No");continue;}for(i = 1; i < tp && mat[topo[i-1]][topo[i]]; ++i);printf(i == tp ? "Yes\n": "No\n");}return 0;}/**28 111 2 2 3 2 5 2 6 3 5 4 3 5 2  5 4 6 7 6  8 7 6*/