http://oj.acm.zstu.edu.cn/JudgeOnline/problem.php?id=4432
题解:二分折半查询。每种硬币有三种选择:选择其中一个,选择其中两个,不选择。
因此共有3^18 种,对总的方案折半,以其中一半为基础,对另一半二分查询是
否存在可能使得构成k。
C++版本一
#include <stdio.h>
#include <set>
std::set<int> st1, st2;
int a[20];
void dfs(int R, int id, int sum, std::set<int> &st){
if (id == R){
st.insert(sum);
return;
}
dfs(R, id+1, sum, st);
dfs(R, id+1, sum+a[id], st);
dfs(R, id+1, sum+2*a[id], st);
}
bool check(int K){
for(std::set<int> ::iterator it = st1.begin(); it != st1.end(); it ++){
if(st2.find(K-*it) == st2.end()) continue;
return true;
}
return false;
}
int main(){
// freopen("baby_coins.in", "r", stdin);
// freopen("baby_coins.out", "w", stdout);
int T, n, K;
int ica = 1;
scanf("%d", &T);
while(T --){
scanf("%d%d", &n, &K);
for(int i = 0; i < n; i ++){
scanf("%d", &a[i]);
}
int ok = false;
if(n == 1){
if(a[0] == K || a[0]*2 == K) ok = 1;
}else{
dfs(n/2, 0, 0, st1);
dfs(n, n/2, 0, st2);
ok = check(K);
}
printf("Case %d: %s\n", ica ++, ok ? "Yes":"No");
st1.clear();
st2.clear();
}
return 0;
}
C++版本二
新思路,我发现上面的方法还是太慢了,基本上要跑100-300ms
如果我们把第二次枚举和查找结合,加上C++的逻辑判断机制,可以大大减少时间到100ms以内
/*
*@Author: STZG
*@Language: C++
*/
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<deque>
#include<stack>
#include<cmath>
#include<list>
#include<map>
#include<set>
//#define DEBUG
using namespace std;
typedef long long ll;
const int N=20;
const double PI = acos(-1.0);
const double EXP = 1E-8;
const int INF = 0x3f3f3f3f;
int t,n,m,k,ans;
set<int> st;
int a[N];
void dfs1(int R, int id, int sum){
if (id == R){
st.insert(sum);
return;
}
dfs1(R, id+1, sum);
dfs1(R, id+1, sum+a[id]);
dfs1(R, id+1, sum+2*a[id]);
}
bool dfs2(int R, int id, int sum){
if (id == R){
if(st.find(k-sum) != st.end())
return true;
return false;
}
return dfs2(R, id+1, sum)||dfs2(R, id+1, sum+a[id])||dfs2(R, id+1, sum+2*a[id]);
}
int main()
{
#ifdef DEBUG
freopen("input.in", "r", stdin);
//freopen("output.out", "w", stdout);
#endif
scanf("%d",&t);
int T=0;
while(t--){
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
ans=0;
if(n == 1){
if(a[0] == k || a[0]*2 == k) ans = 1;
}else{
dfs1(n/2, 0, 0);
ans=dfs2(n, n/2, 0);
}
if(ans){
cout << "Case "<<++T<<": Yes" << endl;
}else{
cout << "Case "<<++T<<": No" << endl;
}
st.clear();
}
//cout << "Hello world!" << endl;
return 0;
}
即使这样依然不是最快的的,大佬已经把时间压缩到56ms,23333