首先对于所有的无向边,我们使用并查集将两边的点并起来 若一条边未合并之前,两端的点已经处于同一个集合了,那么说明必定存在可行的环(因为这两个点处于同一个并查集集合中,那么它们之间至少存在一条路径) 如果上一步没有判断出环,那么仅靠无向边是找不到环的 考虑到,处于同一个并查集集合中的点之间必定存在一条路径互达,因此将一个集合的点合并之后,原问题等价于在新生成的有向图中是否有环我们知道,有向无环图必定存在拓扑序,因此只需使用拓扑排序判定即可
///并查集+强连通 #pragma comment(linker, "/STACK:102400000,102400000") # include <stdio.h> #include <string.h> # include <algorithm> # include <vector> using namespace std; #define MAXN 1001000 vector<int>g[MAXN]; int f[MAXN]; int n; int flag; int scnt,top,tot,cnt; int instack[MAXN],first[MAXN],Stack[MAXN],DFN[MAXN],Low[MAXN]; int Belong[MAXN]; int find(int x) { if(x==f[x]) return x; return f[x]=find(f[x]); } void init() { for(int i=0; i<=n; i++) { f[i]=i; g[i].clear(); } } void Tarjan(int v) { int t; if(flag) return ; DFN[v]=Low[v]=++tot; instack[v]=1; Stack[top++]=v; for(int i=0; i<g[v].size(); i++) { int j=g[v][i]; if(!DFN[j]) { Tarjan(j); if(Low[v]>Low[j]) Low[v]=Low[j]; } else if(instack[j]&&DFN[j]<Low[v]) Low[v]=DFN[j]; } if(DFN[v]==Low[v]) { scnt++; cnt=0; do { t=Stack[--top]; instack[t]=0; cnt++; Belong[t]=scnt; } while(t!=v); if(cnt>=2) { flag=1; return ; } } } void slove() { flag=0; cnt=0; scnt=top=tot=0; memset(first,-1,sizeof(first)); memset(DFN,0,sizeof(DFN)); for(int i=1; i<=n; i++) { if(flag) break; if(!DFN[i]&&f[i]==i) Tarjan(f[i]); } if(flag) { printf("YES\n"); } else printf("NO\n"); return ; } int main() { int T,m1,m2,f1,f2,a,b; scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&m1,&m2); init(); flag=0; for(int i=0; i<m1; i++) { scanf("%d%d",&a,&b); f1=find(a); f2=find(b); if(f1==f2) flag=1; else f[f1]=f2; } for(int i=0; i<m2; i++) { scanf("%d%d",&a,&b); f1=find(a); f2=find(b); if(f1==f2) flag=1; if(flag) continue; g[f1].push_back(f2); } if(flag) printf("YES\n"); else slove(); } return 0; }
///并查集+拓扑 # include <cstdio> # include <algorithm> # include <vector> #include <cstring> #pragma comment(linker, "/STACK:102400000,102400000") using namespace std; const int MAXN=2000005; int f[MAXN]; int vis[MAXN]; vector<int>g[MAXN]; int n,m1,m2; int find(int x) { if(x==f[x]) return x; return f[x]=find(f[x]); } bool dfs(int v) { vis[v]=-1; for(int i=0; i<g[v].size(); i++) { int e=g[v][i]; if(vis[e]<0) return false; if(!vis[e]&&!dfs(e)) return false; } vis[v]=1; return true; } int slove() { memset(vis,0,sizeof(vis)); for(int i=1; i<=n; i++) { int e=find(i); if(!vis[e]) { if(!dfs(e)) return true; } } return false; } void init() { for(int i=1; i<=n; i++) { f[i]=i; g[i].clear(); } } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m1,&m2); init(); getchar(); int a,b,flag=0; for(int i=0; i<m1; i++) { scanf("%d%d",&a,&b); int f1=find(a); int f2=find(b); if(f1!=f2) f[f1]=f2; else flag=1; } for(int i=0; i<m2; i++) { scanf("%d%d",&a,&b); if(!flag) { int f1=find(a); int f2=find(b); g[f1].push_back(f2); } } if(flag) printf("YES\n"); else { if(slove()) printf("YES\n"); else printf("NO\n"); } } return 0; }
hdu Exploration (并查集 拓扑 强连通)
最新推荐文章于 2018-03-11 15:01:00 发布