codeforces 468B Two Sets 并查集变形

题目链接:http://codeforces.com/problemset/problem/468/B

题目大意:给你N个互不相同的整数,再给两个整数a,b,问能否把这N个数分成两部分,使得在a这个集合中的任一个数ai,都存在a-ai也在a 这个集合中,对b集合也同理。如果不存在一种合理分法,输出No,否则输出YES,并输出任一种合理分组。

解题思路:

首先我们先假设存在一种合理的方案,则有  对于任一个数x,肯定在a,b集合中的一个。同时如果方案合理,最后的结果a,b集合中的元素没有交集。

1.对于一个数x,如果a-x不存在,则x肯定在b分组中(假定分组成立),则把x和b分组并起来;如果同时b-x也不存在的话,则再把x和a分组并起来,此时a和b分组被并了起来,显然这种方案不合理。

2.对于一个数x,如果a-x存在,则把x和a-x对应的下标并起来,此时并不能说明x属于集合a,因为可能存在N=2,a=8,b=20,4,16,这样的数据,只有当b-x不存在时,才把x和a的下标并起来。

3,如果b-x也存在时,就把x和b-x也的下标也并起来,此时如果x!=a-x!=b-x时,说明a和b集合公用x,即这种方案a和b被并起来,这种方案也不合理。此时如果x==a-x!=b-x,显然应分组为b,当然特例就是a和b相等,此时任何分组都可以。

总的情况应该这几种。

对于代码,有以下几点感觉很好:

1,map映射,使得查找成对的数字查找更方便。

2,虚拟出两个a,b集合的根结点n+1和n+2;

3,并查集的特殊处理;

代码如下:

#include<stdio.h>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
#define N 100005
int f[N],num[N];
map <int ,int> mp;
int find(int x)  {return x!=f[x]?f[x]=find(f[x]):f[x];}
void merge(int x,int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy)
        f[fx]=fy;
    return;
}
int main()
{
    int n,a,b;
    scanf("%d%d%d",&n,&a,&b);
    for(int i=1;i<=n+2;i++)
        f[i]=i;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&num[i]);
        mp[num[i]]=i;
    }
    for(int i=1;i<=n;i++)
    {
        if(mp[a-num[i]]) merge(i,mp[a-num[i]]);
        else merge(i,n+2);
        if(mp[b-num[i]]) merge(i,mp[b-num[i]]);
        else merge(i,n+1);
    }
    if(find(n+1)==find(n+2))
        printf("NO\n");
    else
    {
        printf("YES\n");
        for(int i=1;i<=n;i++)
        {
            if(find(i)==find(n+1)) printf("0 ");
            else printf("1 ");
        }
        printf("\n");
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值