官方题解:http://acdream.info/topic?tid=4246
参考:https://www.cnblogs.com/nowandforever/p/4492428.html
题意:在给定的n个数中,能否找到几个数使得这几个和等于H;
思路:注意这道题的条件 0<n<=40, 0<=H<10^9, 0<=a[i]<10^9,其中 H 和 A [i] 给的比较大,dp的空间开不下,而n比较小,只有40,所以可以把所给的数分成20、20两部分,用dfs或者直接状态压缩从0至2^(n/2)循环来搞出每组所有可能的和(dfs+剪枝应该比循环快),然后再在第二部分找(H-第一部分的可能和)就可以了。卡了一下map和set。可以用hash或者二分来找
ac代码(600+ms):
#include <cstdio> #include <algorithm> using namespace std; const int maxn = 1050000; //比2的20次大一点 int n,h,a[50],d[50],c[maxn],cnt,flag; int check(int s) { int le=1,ri=cnt; while(le<=ri) { int mid=(le+ri)>>1; if(c[mid]==s)return 1; if(c[mid]>s) ri = mid - 1; else le = mid + 1; } return 0; } void dfs(int sum,int cur,int nn,int on)//利用on使得两次dfs放在了一起 { if(flag)return; if(cur==nn+1) { if(on) c[++cnt]=sum; else flag = check(h-sum); return; } for(int i=0;i<2;i++) { int t=sum+d[cur]*i; if(t > h)return; dfs(t,cur+1,nn,on); } } int main(){ //freopen("in","r",stdin); while(~scanf("%d%d",&n,&h)) { for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); } cnt = flag = 0; int n1 = (n>>1), n2=n-n1;//(n>>1)没加括号WA了几次 for(int i=1; i<=n1; i++) { d[i]=a[i]; } dfs(0,1,n1,1); //第一次先算出前一半的所有可能和; sort(c+1,c+cnt+1); for(int i=n1+1;i<=n;i++) { d[i-n1]=a[i]; } dfs(0,1,n2,0); //第二次求后一半的和 ,在用二分在前一半中找有没有对应的值 if(flag)puts("Yes"); else puts("No"); } return 0; }