Hand in Hand 【HDU - 3926】【带权并查集】

题目链接


  很好的一道题,关于同构图,一开始没理解,而且他给的数据也很坑,我开始以为完全一样的图就是同构图,但是,很显然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;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值