cf 468B Two Sets | dfs、二分搜索

题意:

给你n个数,让你把它们分为两个集合(集合可以为空)。

要求,如果过把 x 放到A集合中,a - x必须也在A集合中;同理,把 x 放到B集合中,b-x也要在B集合中。

如果可以满足要求输出YES,并输出分配情况;否则输出NO。

思路:

*我开始还以为n为奇数时一定是NO,像6 - 3 = 3这种情况要注意一下。

x1—(a)—x2—(b)—x3—(a)—x4—(b)—x5…… (表示x1+x2 = a,x2+x3 = b,x3+x4 = a……)

给我一个x,我就会按上面的链进行dfs。

记相加为a的个数为cota,相加为b的个数为cotb。

如果cota == cotb,说明无论怎么分都会有冲突。

否则择其大者而放之,即如果cota > cotb,把这次dfs所遇到的点,全部放入A组中。否则,全部放入B组。

AC代码:(代码写得比较麻烦)

#include <cstring>
#include <cstdlib>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
typedef long long LL;
const int MAXN = 1e5+5;
int ycsm[MAXN];
struct em
{
        int v, s, index;
}d[MAXN];
bool cmp(em t, em c)
{
        return t.v < c.v;
}
bool cmp2(em a, em b)
{
        return a.index < b.index;
}
int cota, cotb, cot;
int n, a, b;
int bs(int tmp)         //get the tmp's index;
{
        int l = 0, r = n-1;
        while(l <= r)
        {
                int mid = (l+r)/2;
                if(d[mid].v == tmp)     return mid;
                if(d[mid].v < tmp)      l = mid+1;
                else    r = mid-1;
        }
        return -1;
}
void dfs(int val, int ab)
{
        int tmp, next;
        if(ab == 0)
        {
                tmp = a-val, next = bs(tmp);            //next is index;
                if(next == -1)  return;
                ycsm[cot++] = next;
                cota++;
                dfs(tmp, 1);
        }
        else if(ab == 1)
        {
                tmp = b-val;
                next = bs(tmp);
                if(next == -1)  return;
                ycsm[cot++] = next;
                cotb++;
                dfs(tmp, 0);
        }
        else
        {
                next = bs(a-val);
                if(next != -1)
                {
                        cota++;
                        ycsm[cot++] = next;
                        dfs(a-val, 1);
                }
                //
                next = bs(b-val);
                if(next != -1)
                {
                        cotb++;
                        ycsm[cot++] = next;
                        dfs(b-val, 0);
                }
        }
}
        
int main()
{
        //input
        cin>>n>>a>>b;
        for(int i = 0;i < n; i++)
        {
                cin>>d[i].v;
                d[i].s = -1;
                d[i].index = i;
        }
        //
        sort(d, d+n, cmp);
        //a == b
        if(a == b)<span style="white-space:pre">		</span>//特判了一下a等于b的情况,不知道有没有。。。
        {
                for(int i = 0;i < n; i++)
                {
                        int tmp = a - d[i].v;
                        int next = bs(tmp);
                        if(next == -1)  return puts("NO"), 0;
                }
                puts("YES");
                for(int i = 0;i < n; i++)
                        printf("0%c",i == n-1?'\n':' ');
                return 0;
        }
        //a != b
        int i, tmp;
        for(i = 0;i < n; i++)
        {
                if(d[i].s != -1)        continue;
                cota = cotb = cot = 0;
                ycsm[cot++] = i;<span style="white-space:pre">			</span>//把当前这个点的下标放入待分配数组。
                dfs(d[i].v, 2);
                if(cota == cotb)        break;<span style="white-space:pre">		</span>//无论怎么放都会有冲突,break
                if(cota > cotb) tmp = 0;<span style="white-space:pre">		</span>
                else    tmp = 1;
                for(int j = 0;j < cot; j++)<span style="white-space:pre">		</span>//更新每个值所对应的组别。
                        d[ycsm[j]].s = tmp;
        }
        if(i != n)     
                puts("NO");
        else
        {
                puts("YES");
                sort(d, d+n, cmp2);
                for(int i = 0;i < n; i++)
                        printf("%d%c",d[i].s,i == n-1?'\n':' ');
        }
        return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值