链接http://vjudge.net/problem/ACdream-1726
官方题解http://acdream.info/topic?tid=4246
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,h,n1,n2,a[50],b[50],c[1050000],cnt;
bool flag=0;
bool check(int x)
{
int l=0,r=cnt-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(c[mid]==x) return 1;
else if(c[mid]>x) r=mid-1;
else l=mid+1;
}
return 0;
}
void dfs(int sum,int deep,int m,int on)
{
if(flag) return; //剪枝
if(deep==m) //到最后一个数
{
if(on) c[cnt++]=sum; //第一次记录 和
else flag=check(h-sum); //第二次查找
return;
}
//sum+=b[deep]*i; //累加和
if(sum>h) return; //剪枝
dfs(sum,deep+1,m,on);
dfs(sum+b[deep],deep+1,m,on);
}
int main()
{
//freopen("a.txt","r",stdin);
while(~scanf("%d%d",&n,&h))
{
cnt=0;
flag=0;
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
n1=n>>1;n2=n-n1; //分成两半
for(int i=n1;i<n;i++)
b[i-n1]=a[i]; //后一半数用b存储
dfs(0,0,n2,1); //枚举所有可能的和
sort(c,c+cnt); //对得到的数组进行排序 便于二分查找
for(int i=0;i<n1;i++)
b[i]=a[i]; //得到前一半的和
dfs(0,0,n1,0); //枚举所有的和
if(flag) puts("Yes");
else puts("No");
}
return 0;
}