Hand in Hand HDU - 3926
给一一副有单环或链的图 判断是否同构
我们可以判断环有多少个,链有多少个,同时判断一下每个环的点数和链的点的个数
第一种做法:
所以,我们可以直接用并查集来做.
同时,我们注意到两幅图的人数应该是一样的.
所以,把并查集修改一下就直接判断了. (如果成环,最后成环的并集会让点的个数加倍. 同时,因为人数是固定的,所以可以直接sort,然后比较)
#include <bits/stdc++.h> using namespace std; int fa[10050]; int id1[10050], id2[10050]; int find(int idx) { return fa[idx] < 0 ? idx : fa[idx] = find(fa[idx]); } inline void Union(int x, int y) { int xf = find(x); int yf = find(y); if (fa[xf] > fa[yf]) swap(xf, yf); fa[xf] = fa[xf] + fa[yf]; if (xf == yf) return ; // 注意 放到这个位置的意义,就是为了判环. fa[yf] = xf; } int main() { int t, n, m, i, v, u, cnt1, cnt2; scanf("%d", &t); for (int cas=1; cas<=t; ++cas) { memset(fa, -1, sizeof(fa)); scanf("%d%d",&n, &m); for (i=1; i<=m; ++i) { scanf("%d%d", &u, &v); Union(u, v); } cnt1 = cnt2 = 0; for (i=1; i<=n; ++i) if (fa[i]<0) id1[cnt1++] = abs(fa[i]); memset(fa, -1, sizeof(fa)); scanf("%d%d", &n, &m); for (i=1; i<=m; ++i) { scanf("%d%d", &u, &v); Union(u, v); } for (i=1; i<=n; ++i) if (fa[i]<0) id2[cnt2++] = abs(fa[i]); printf("Case #%d: ", cas); if (cnt1 != cnt2) { printf("NO\n"); continue; } sort(id1, id1+cnt1); sort(id2, id2+cnt2); for (i=0; i<cnt1; ++i) if (id1[i] != id2[i]) break; if (i==cnt1) printf("YES\n"); else printf("NO\n"); } return 0; }
第二种做法:
我们注意到别个点的度数都只有2.所以我们Tarjan可以根据点的个数和度数来判环.
用Tarjan求连通分量, 同时将每个环和链的典树分别求出.
#include"iostream" #include"cstdio" #include"stack" #include"cstring" #include"algorithm" using namespace std; const int N=10005; int n[2],m[2],cnt_line[2],cnt_cir[2],cnt_line_node[2][N],cnt_cir_node[2][N]; int LOW[N],DFN[N],instack[N],index_s,indegree[2][N]; struct Edge{ int v,next; }edge[2][2*N]; int tot[2],head[2][N]; void add(int k,int a,int b){ edge[k][tot[k]].v=b;edge[k][tot[k]].next=head[k][a];head[k][a]=tot[k]++; edge[k][tot[k]].v=a;edge[k][tot[k]].next=head[k][b];head[k][b]=tot[k]++; } void build_map(int k) { int a,b; tot[k]=0; memset(head[k],-1,sizeof(head[k])); memset(indegree[k],0,sizeof(indegree[k])); scanf("%d%d",&n[k],&m[k]); while(m[k]--) { scanf("%d%d",&a,&b); add(k,a,b); //printf("%d %d \n", a, b); indegree[k][a]++; indegree[k][b]++; } } stack<int>st; void Tarjan(int k,int s) { int j,v; st.push(s); instack[s]=1; DFN[s]=LOW[s]=++index_s; for(j=head[k][s];j!=-1;j=edge[k][j].next) { v=edge[k][j].v; if(instack[v]) LOW[s]=LOW[s]>DFN[v]?DFN[v]:LOW[s]; else if(DFN[v]==-1) { Tarjan(k,v); LOW[s]=LOW[s]>LOW[v]?LOW[v]:LOW[s]; } } if(LOW[s]==DFN[s]) { int cnt_node=0; int cnt_degree=0; do { j=st.top(); st.pop(); instack[j] = 0; cnt_node++; cnt_degree+=indegree[k][j]; }while(j!=s); // printf("---%d %d \n", cnt_node*2, cnt_degree); if(cnt_node*2==cnt_degree) cnt_cir_node[k][cnt_cir[k]++]=cnt_node; else cnt_line_node[k][cnt_line[k]++]=cnt_node; } } void solve(int k) { int i; cnt_line[k]=cnt_cir[k]=0; index_s=0; memset(LOW,-1,sizeof(LOW)); memset(DFN,-1,sizeof(DFN)); memset(instack,0,sizeof(instack)); for(i=1;i<=n[k];i++) if(LOW[i]==-1) Tarjan(k,i); } int main() { // freopen("E:\\input.txt", "r", stdin); int T,Case; int i; int ans; cin>>T; for(Case=1;Case<=T;Case++) { build_map(0); build_map(1); solve(0); solve(1); // printf("%d %d \n", cnt_cir[0], cnt_line[0]); // printf("%d %d \n", cnt_cir[1], cnt_line[1]); ans=0; if(cnt_line[0]!=cnt_line[1] || cnt_cir[0]!=cnt_cir[1]) ans=1; if(ans) {printf("Case #%d: NO\n",Case);continue;} sort(cnt_line_node[0],cnt_line_node[0]+cnt_line[0]); sort(cnt_line_node[1],cnt_line_node[1]+cnt_line[1]); for(i=0;i<cnt_line[0];i++) if(cnt_line_node[0][i]!=cnt_line_node[1][i]) {ans=1;break;} if(ans) {printf("Case #%d: NO\n",Case);continue;} sort(cnt_cir_node[0],cnt_cir_node[0]+cnt_cir[0]); sort(cnt_cir_node[1],cnt_cir_node[1]+cnt_cir[1]); for(i=0;i<cnt_cir[0];i++) if(cnt_cir_node[0][i]!=cnt_cir_node[1][i]) {ans=1;break;} if(ans) printf("Case #%d: NO\n",Case); else printf("Case #%d: YES\n",Case); } return 0; }