题目链接
很好的一道题,关于同构图,一开始没理解,而且他给的数据也很坑,我开始以为完全一样的图就是同构图,但是,很显然WA告诉我,你这么想是错的,于是我就去百度了下什么是同构图,原来结构相似的就是同构图,就是一个五角星和一个五边形可以看作是一对同构图。
然后,我们讲讲解题思路:我们看到这道题,他说的是每个点最多可以连出两条边,那么,最后所得到的图不是链就是环,所以我们对所有的链上的节点,排序后查它们的子节点的个数是否对应相等;对所有的环,排序后查它们的子节点的个数是否也是对应相等,所以就是判断了。那么既然有环、又有链,我们不妨定义个结构体来判断其是否是链或者环。
最后说一下,我们查子节点当然是用带权并查集的,但是这儿的带权并查集还有些不一样,你得令特定状态的根节点链接到另一个上面,譬如说,把子节点值少的链接到子节点值多的上去,目的就是为了避免少,或者有些值不同而影响最后的结果。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN=10005;
int N, M, n, m, root[maxN];
struct node
{
int sum, huan;
node(int a=1, int b=0):sum(a), huan(b) {}
}a1[maxN], a2[maxN];
void init(int x)
{
for(int i=1; i<=x; i++) root[i]=i;
}
int fid(int x) { return x==root[x]?x:(root[x]=fid(root[x])); }
bool cmp(node e1, node e2) { return e1.huan==e2.huan?(e1.sum>e2.sum):(e1.huan>e2.huan); }
int main()
{
int T; scanf("%d", &T);
for(int Cas=1; Cas<=T; Cas++)
{
scanf("%d%d", &N, &M);
for(int i=1; i<maxN; i++) { a1[i]=node(); a2[i]=node(); }
init(N);
int e1, e2, u, v;
for(int i=1; i<=M; i++)
{
scanf("%d%d", &e1, &e2);
u=fid(e1); v=fid(e2);
if(a1[u].sum>a1[v].sum) swap(u, v);
if(u!=v)
{
root[u]=v;
a1[v].sum+=a1[u].sum;
a1[v].huan=0;
}
else a1[v].huan=1;
}
scanf("%d%d", &n, &m);
init(n);
for(int i=1; i<=m; i++)
{
scanf("%d%d", &e1, &e2);
u=fid(e1); v=fid(e2);
if(a2[u].sum>a2[v].sum) swap(u, v);
if(u!=v)
{
root[u]=v;
a2[v].sum+=a2[u].sum;
a2[v].huan=0;
}
else a2[v].huan=1;
}
bool flag = true;
if(N != n) flag=false;
sort(a1+1, a1+1+N, cmp);
sort(a2+1, a2+1+n, cmp);
for(int i=1; i<=N; i++)
{
if(a1[i].sum!=a2[i].sum || a1[i].huan!=a2[i].huan || !flag)
{
flag = false;
break;
}
}
printf("Case #%d: ", Cas);
printf(flag?"YES\n":"NO\n");
}
return 0;
}