HDU 3926 Hand in Hand 并查集

求图的同构

因为只有两个度,所以每个分量只可能链表或环

用并查集判断链表和环的数量以及每个链表和环上的节点个数是否相等

相等即相似,反之不相似

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define BUG puts("HERE!")
#define IN1(A) scanf("%d", &(A))
#define IN2(A, B) scanf("%d%d", &(A), &(B))
using namespace std;
const int MAX = 1e4 + 5;
const int INF = 0x7fffff;
int f[MAX], cnt[MAX];
int Cnum1[MAX], Lnum1[MAX];
int Cnum2[MAX], Lnum2[MAX];
int Ccnt1, Lcnt1;
int Ccnt2, Lcnt2;
bool isl[MAX];

void init(int n){
	for (int i = 0; i <= n; ++i){
		f[i] = i;
		cnt[i] = 1;
	}
	memset(isl, true, sizeof(isl));
}

struct _edge{
	int s, t;
	bool operator < (const _edge& a) const {
		if(s != a.s)
			return s < a.s;
		return t < a.t;
	}
	bool operator != (const _edge& a) const {
		return s != a.s || t != a.t;
	}
}a[MAX], b[MAX];

int find(int x){
	return x == f[x] ? x : f[x] = find(f[x]);
}

int uni(int a, int b, int& Ccnt, int* Cnum){
	int fa = find(a), fb = find(b);
	if(fa == fb){
		Cnum[Ccnt++] = cnt[fa] + cnt[fb];
		isl[fa] = false, isl[fb] = false;
		return 1;
	}
	else
		cnt[fa] += cnt[fb], f[fb] = fa;
	return 0;
}

int uq(_edge* s, int m){
	int cnt = 0;
	for(int i = 0; i < m; ++i)
		if(i == m - 1 || s[i] != s[i + 1])
			s[cnt++] = s[i]; 
	return cnt;
}

int main(int argc, char const *argv[]){

#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
	// freopen("out.out", "w", stdout);
#endif

	int ca, n_1, m_1, n_2, m_2;
	int s, t, cas = 1;
	IN1(ca);
	while (ca --){
		Lcnt1 = 0, Lcnt2 = 0;
		Ccnt1 = 0, Ccnt2 = 0;
		IN2(n_1, m_1);
		init(n_1);
		for (int i = 0; i < m_1; ++i){
			IN2(a[i].s, a[i].t);
		}
		sort(a, a + m_1);
		for (int i = 0; i < m_1; ++i){
			uni(a[i].s, a[i].t, Ccnt1, Cnum1);
		}
		for (int i = 1; i <= n_1; ++i){
			if(isl[i] && find(i) == i)
				Lnum1[Lcnt1++] = cnt[i];
		}
		IN2(n_2, m_2);

		init(n_2);
		for (int i = 0; i < m_2; ++i){
			IN2(b[i].s, b[i].t);
		}
		sort(b, b + m_2);
		for (int i = 0; i < m_2; ++i){
			uni(b[i].s, b[i].t, Ccnt2, Cnum2);
		}
		for (int i = 1; i <= n_2; ++i){
			if(isl[i] && find(i) == i)
				Lnum2[Lcnt2++] = cnt[i];
		}
		sort(Lnum1, Lnum1 + Lcnt1);
		sort(Lnum2, Lnum2 + Lcnt2);
		sort(Cnum1, Cnum1 + Ccnt1);
		sort(Cnum2, Cnum2 + Ccnt2);
		bool flag = true;
		if(Lcnt1 == Lcnt2&& Ccnt1 == Ccnt2){
			for(int i = 0; i < Lcnt1; ++i)
				if(Lnum1[i] != Lnum2[i]){
					flag = false;
					break;
				}
			if(flag){
				for(int i = 0; i < Ccnt1; ++i)
					if(Cnum1[i] != Cnum2[i]){
						flag = false;
						break;
					}
			}
			else
				flag = false;
		}
		else
			flag = false;
		if(flag)
			printf("Case #%d: YES\n", cas++);
		else
			printf("Case #%d: NO\n", cas++);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值