Baby Coins

题意

描述

Baby 今天清点自己的百宝箱啦,箱子里有n 种硬币,硬币的面值分别是:val[1],val[2],...,val[n],每种面值的硬币都恰好有2 个。

Baby 实在闲的太无聊了,他想从他所拥有的硬币中选出若干个,使得面值之和为k。那么他的目标能否实现呢~

输入

先输入T,代表数据一共有T 组,(T ≤ 100)

每一组数据第一行都包含两个数字n(n≤18),k(1≤k≤109)

n 代表箱子中所包含的硬币种数,k 代表Baby 需要组成的金钱数额。

接下来的一行代表val[1],val[2],......,val[n]。(1≤val[i]≤ 10^7)

输出

如果Baby能组成金钱数额k,请输出Yes,否则输出No。

输入样例 1

2
2 10
3 4
3 9
1 2 10
输出样例 1

Case 1: Yes
Case 2: No

分析

每种硬币可以取 0或1或2个
所以有3^18种,暴力复杂度是很高的。所以想办法解决问题
把一半种硬币的各种组合值存在一个set里,其他在另一个set里。
最后看两个set能不能凑到k即可
set.find()的复杂度是log所以降低了整体复杂度

代码

#include<iostream>
#include<set>
using namespace std;
set<int> se1,se2;
int a[20];
void all(int up,int low,int sum,std::set<int> &se){
    if(low==up){
        se.insert(sum); return;
    }
    all(up,low+1,sum,se);
    all(up,low+1,sum+a[low],se);
    all(up,low+1,sum+2*a[low],se);
}
bool ok(int k){
    for(set<int> ::iterator it=se1.begin();it!=se1.end();it++){
        if(se2.find(k-*it)==se2.end()) continue;
        return true;
    }
    return false;
}
int main(){
    int t,n,k,kase=0;
    //freopen("in.txt","r",stdin);
    cin>>t;
    while(t--){
        cin>>n>>k;
        for(int i=0;i<n;i++) cin>>a[i];
        bool g=false;
        if(n==1){
            if(k==a[0]||k==2*a[0]) g=true;
        }
        else{
            se1.clear(),se2.clear();
        all(n/2,0,0,se1);
        all(n,n/2,0,se2);
         g=ok(k);
         cout<<"Case "<<++kase<<": "<<(g?"Yes\n":"No\n");
        }
    }
    return 0;
}
posted @ 2019-01-18 19:52  ChunhaoMo  阅读(178)  评论(0)    收藏  举报