http://blog.csdn.net/wsniyufang/article/details/6609872
题意:判断给定的有向图是否满足 1.强连通 2 每一条边属于且仅属于一个环
分析:tarjan算法的运用,用fa[]数组记录tarjand的搜索路径,当有一个点有横向边(指向它的祖先节点——表示有环),据fa记录的路径标记 除被指向的祖先外所有路径上的点,当有某个点被记录2次时,必然存在一条边属于两个环。
我的程序有点错误,在UVA10510 - Cactus老是RE...不知道为啥..然后改了下输入到hdu上就过了...难道是hdu的数据太弱了?唉..我好菜(顶点改成从0开始就好了!)
//UVA
// File Name: 10510.cpp // Author: Zlbing // Created Time: 2013/4/28 11:04:30 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,r,n) for(int i=r;i<=n;i++) #define RREP(i,n,r) for(int i=n;i>=r;i--) const int MAXN=2e4+100; int n,m; vector<int>G[MAXN]; int lowlink[MAXN],sccno[MAXN],pre[MAXN]; int scc_cnt,dfs_clock; stack<int> S; int flag; int visiting[MAXN]; int fa[MAXN],out[MAXN]; void find(int v,int u) { while(fa[u]!=v) { out[u]++; if(out[u]>1){ flag=1; return; } u=fa[u]; } } void dfs(int u) { if(flag)return; pre[u]=lowlink[u]=++dfs_clock; S.push(u); visiting[u]=1; int cnt=0; for(int i=0;i<G[u].size();i++) { int v=G[u][i]; if(!pre[v]) { fa[v]=u; dfs(v); lowlink[u]=min(lowlink[u],lowlink[v]); }else if(visiting[v]) { lowlink[u]=min(lowlink[u],pre[v]); find(v,u); if(flag)return; } } if(lowlink[u]==pre[u]) { scc_cnt++; if(scc_cnt>1){ flag=1; return; } for(;;){ int t=S.top();S.pop(); sccno[t]=scc_cnt; visiting[t]=0; if(t==u)break; } } } void find_scc(){ memset(sccno,0,sizeof(sccno)); memset(lowlink,0,sizeof(lowlink)); memset(pre,0,sizeof(pre)); dfs_clock=0,scc_cnt=0; for(int i=0;i<n;i++) if(!pre[i]){ dfs(i); if(flag) return; } } int main() { int cas; scanf("%d",&cas); while(cas--) { scanf("%d%d",&n,&m); int a,b; REP(i,0,n)G[i].clear(); REP(i,1,m) { scanf("%d%d",&a,&b); G[a].push_back(b); } flag=0; CL(visiting,0); CL(out,0); find_scc(); if(flag) printf("NO\n"); else printf("YES\n"); } return 0; }
//HDU
// File Name: 10510.cpp // Author: Zlbing // Created Time: 2013/4/28 11:04:30 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,r,n) for(int i=r;i<=n;i++) #define RREP(i,n,r) for(int i=n;i>=r;i--) const int MAXN=2e4+100; int n,m; vector<int>G[MAXN]; int lowlink[MAXN],sccno[MAXN],pre[MAXN]; int scc_cnt,dfs_clock; stack<int> S; int flag; int visiting[MAXN]; int fa[MAXN],out[MAXN]; void find(int v,int u) { while(fa[u]!=v) { out[u]++; if(out[u]>1){ flag=1; return; } u=fa[u]; } } void dfs(int u) { if(flag)return; pre[u]=lowlink[u]=++dfs_clock; S.push(u); visiting[u]=1; int cnt=0; for(int i=0;i<G[u].size();i++) { int v=G[u][i]; if(!pre[v]) { fa[v]=u; dfs(v); lowlink[u]=min(lowlink[u],lowlink[v]); }else if(visiting[v]) { lowlink[u]=min(lowlink[u],pre[v]); find(v,u); if(flag)return; } } if(lowlink[u]==pre[u]) { scc_cnt++; if(scc_cnt>1){ flag=1; return; } for(;;){ int t=S.top();S.pop(); sccno[t]=scc_cnt; visiting[t]=0; if(t==u)break; } } } void find_scc(){ memset(sccno,0,sizeof(sccno)); memset(lowlink,0,sizeof(lowlink)); memset(pre,0,sizeof(pre)); dfs_clock=0,scc_cnt=0; for(int i=1;i<=n;i++) if(!pre[i]){ dfs(i); if(flag) return; } } int main() { int cas; scanf("%d",&cas); while(cas--) { int a,b; scanf("%d",&n); REP(i,0,n)G[i].clear(); while(true) { scanf("%d%d",&a,&b); if(a==0&&b==0)break; G[a+1].push_back(b+1); } flag=0; CL(visiting,0); CL(out,0); find_scc(); if(flag) printf("NO\n"); else printf("YES\n"); } } /* int main() { int cas; scanf("%d",&cas); while(cas--) { scanf("%d%d",&n,&m); int a,b; REP(i,0,n)G[i].clear(); REP(i,1,m) { scanf("%d%d",&a,&b); G[a+1].push_back(b+1); } flag=0; CL(visiting,0); CL(out,0); find_scc(); if(flag) printf("NO\n"); else printf("YES\n"); } return 0; } */
这里有个说仙人掌图分析的文章,写的很好,也可以用这里面的结论写
性质 1 仙人掌图的 DFS树没有横向边。
性质 2 Low(u)<=pre(v) (u是 v 的儿子)
性质 3 设某个点 v有 a(v)个儿子的 Low值小于 DFS(v),同时 v自己有 b(v)条逆向边。
那么 a(v)+b(v)<2。
https://files.cnblogs.com/ambition/cactus_solution.pdf
//HDU
// File Name: 10510.cpp // Author: Zlbing // Created Time: 2013/4/28 11:04:30 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,r,n) for(int i=r;i<=n;i++) #define RREP(i,n,r) for(int i=n;i>=r;i--) const int MAXN=2e4+100; int n,m; vector<int>G[MAXN]; int lowlink[MAXN],sccno[MAXN],pre[MAXN]; int scc_cnt,dfs_clock; stack<int> S; int flag; int visiting[MAXN]; int hh[MAXN]; void dfs(int u) { if(flag)return; pre[u]=lowlink[u]=++dfs_clock; S.push(u); visiting[u]=1; int cnt=0; for(int i=0;i<G[u].size();i++) { int v=G[u][i]; //性质1有横边 if(hh[v]){ flag=1; return; } if(!pre[v]) { dfs(v); if(lowlink[v]<pre[u]) cnt++; //性质三 if(cnt>=2) { flag=1; return; } lowlink[u]=min(lowlink[u],lowlink[v]); }else if(visiting[v]) { lowlink[u]=min(lowlink[u],pre[v]); cnt++; //性质三 if(cnt>=2) { flag=1; return; } } } if(lowlink[u]==pre[u]) { scc_cnt++; if(scc_cnt>1){ flag=1; return; } for(;;){ int t=S.top();S.pop(); sccno[t]=scc_cnt; visiting[t]=0; if(t==u)break; } } hh[u]=1; } void find_scc(){ memset(sccno,0,sizeof(sccno)); memset(lowlink,0,sizeof(lowlink)); memset(pre,0,sizeof(pre)); dfs_clock=0,scc_cnt=0; for(int i=1;i<=n;i++) if(!pre[i]){ dfs(i); if(flag) return; } } int main() { int cas; scanf("%d",&cas); while(cas--) { int a,b; scanf("%d",&n); REP(i,0,n)G[i].clear(); while(true) { scanf("%d%d",&a,&b); if(a==0&&b==0)break; G[a+1].push_back(b+1); } flag=0; CL(visiting,0); CL(hh,0); find_scc(); if(flag) printf("NO\n"); else printf("YES\n"); } } /* int main() { int cas; scanf("%d",&cas); while(cas--) { scanf("%d%d",&n,&m); int a,b; REP(i,0,n)G[i].clear(); REP(i,1,m) { scanf("%d%d",&a,&b); G[a+1].push_back(b+1); } flag=0; CL(visiting,0); CL(out,0); find_scc(); if(flag) printf("NO\n"); else printf("YES\n"); } return 0; } */