POJ2762判断图是否单向连通,缩点+dfs
来源:互联网 发布:java语言的编译原理 编辑:程序博客网 时间:2024/05/22 09:38
/*题意:判断所给图是否为单向连通图先Tarjan缩点;对于缩点之后的图的每一条边正反两个方向DFS,分别统计由这条边出去(out)和进来(in)能到达的点数,将统计的结果加到边所连接的两点上去,边的起点+out的结果,边的终点加上in的结果,最后判断每个点的结果是否为总点数-1。写完后google一下,证明我的原创算法又不是主流的算法,。。。其实当且仅当缩点后的图为一条单链时,图为单向连通图,这样dfs就好写多了,看poj status 别个的时间也不比俺优,哈哈*/#include <cstdio>#include <cstring>#include <iostream>#include <vector>using namespace std;const int NN=1005;const int MM=10000;vector<int> adj[NN];int n,m;struct Edge{ //缩点后的边,next双域存正反两个方向 int u,v,next1,next2;}e[MM];int ecnt,head1[NN],head2[NN];void addedge(int u,int v){ ecnt++; e[ecnt].u=u; e[ecnt].v=v; e[ecnt].next1=head1[u]; e[ecnt].next2=head2[v]; head1[u]=head2[v]=ecnt;}int depth,top,bcnt;int dfn[NN],low[NN],belong[NN],stack[NN];bool instack[NN];void tarjan(int u){ dfn[u]=low[u]=++depth; stack[++top]=u; instack[u]=true; int v; for (int i=0; i<adj[u].size(); i++) { v=adj[u][i]; if (!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if (instack[v]) low[u]=min(low[u],dfn[v]); } if (low[u]==dfn[u]) { bcnt++; do{ v=stack[top--]; instack[v]=false; belong[v]=bcnt; }while (v!=u); }}int in[NN],out[NN];void out_dfs(int i){ if (out[i]) return; int u=e[i].v; for (int j=head1[u]; j!=-1; j=e[j].next1) { out_dfs(j); out[i]+=out[j]; } out[i]+=1;}void in_dfs(int i){ if (in[i]) return; int u=e[i].u; for (int j=head2[u]; j!=-1; j=e[j].next2) { in_dfs(j); in[i]+=in[j]; } in[i]+=1;}int r[NN];bool ok(){ bcnt=top=depth=0; for (int i=1; i<=n; i++) { instack[i]=false; dfn[i]=0; } for (int i=1; i<=n; i++) if (!dfn[i]) tarjan(i); if (bcnt==1) return true; //图是强连通的可提前退出 ecnt=0; for (int i=1; i<=bcnt; i++) head1[i]=head2[i]=-1; for (int u=1; u<=n; u++) { for (int i=0; i<adj[u].size(); i++) { int v=adj[u][i]; if (belong[u]!=belong[v]) addedge(belong[u],belong[v]); } } for (int i=1; i<=ecnt; i++) out[i]=in[i]=0; for (int i=1; i<=ecnt; i++) out_dfs(i),in_dfs(i); for (int i=1; i<=bcnt; i++) r[i]=0; for (int i=1; i<=ecnt; i++) { r[e[i].u]+=out[i]; r[e[i].v]+=in[i]; } for (int i=1; i<=bcnt; i++) if (r[i]!=bcnt-1) return false; return true;}int main(){ int cas,x,y; scanf("%d",&cas); while (cas--) { scanf("%d%d",&n,&m); for (int i=1; i<=n; i++) adj[i].clear(); for (int i=1; i<=m; i++) { scanf("%d%d",&x,&y); adj[x].push_back(y); } if (ok()) printf("Yes\n"); else printf("No\n"); } return 0;}