码迷,mamicode.com
首页 > 其他好文 > 详细

ACdream 1726 A Math game (dfs+二分)

时间:2015-05-10 17:00:36      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:

http://acdream.info/problem?pid=1726

官方题解:http://acdream.info/topic?tid=4246

求n个数里面能不能选一些数出来让它们的和等于k。

因为k很大,不能用背包,但是n很小,最大为40,所以拆成了2部分,之后最大为2^20次方<1050000;每次枚举前一半的和,然后用数组存储,然后得到一个总和减去后一半的差用二分查找。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int n,h,n1,n2,a[50],b[50],c[1050000],cnt;
 7 bool flag=0;
 8 
 9 bool check(int x)
10 {
11     int l=0,r=cnt-1;
12     while(l<=r)
13     {
14         int mid=(l+r)>>1;
15         if(c[mid]==x) return 1;
16         else if(c[mid]>x) r=mid-1;
17         else l=mid+1;
18     }
19     return 0;
20 }
21 void dfs(int sum,int deep,int m,int on)
22 {
23     if(flag) return;  //剪枝
24     if(deep==m)  //到最后一个数
25     {
26         if(on) c[cnt++]=sum;  //第一次记录 和
27         else flag=check(h-sum); //第二次查找
28         return;
29     }
30     for(int i=0;i<2;i++)
31     {
32         sum+=b[deep]*i;   //累加和
33         if(sum>h) return;  //剪枝
34         dfs(sum,deep+1,m,on);
35     }
36 }
37 int main()
38 {
39     //freopen("a.txt","r",stdin);
40     while(~scanf("%d%d",&n,&h))
41     {
42         cnt=0;
43         flag=0;
44         for(int i=0;i<n;i++)
45             scanf("%d",&a[i]);
46         n1=n>>1;n2=n-n1;   //分成两半
47         for(int i=n1;i<n;i++)
48             b[i-n1]=a[i]; //后一半数用b存储
49         dfs(0,0,n2,1); //枚举所有可能的和
50         sort(c,c+cnt);  //对得到的数组进行排序 便于二分查找
51         for(int i=0;i<n1;i++)
52             b[i]=a[i];  //得到前一半的和
53         dfs(0,0,n1,0);  //枚举所有的和
54         if(flag) puts("Yes");
55         else puts("No");
56     }
57     return 0;
58 }

 

ACdream 1726 A Math game (dfs+二分)

标签:

原文地址:http://www.cnblogs.com/nowandforever/p/4492428.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!