hdu 5616 Jam's balance 正反背包+转换

http://acm.hdu.edu.cn/showproblem.php?pid=5616

思路

题目中蕴含着两种需要计算的重量

1. 从所有的砝码中挑出任意种
2.(转换的思想)在天平的两端都挑出这些砝码中的一些,它也可以计算出差值,这个差值也是一种重量
    这其实一种转换,看下面这个公式(左端砝码的重量)==(右端砝码的重量+能计算出的重量G)
    当第一次选择一个砝码,我们计算出了以第二种方式的一种重量G,那么它也要被记为true,它还可以
    继续更新出新的重量,G(新的左端砝码重量)=(右端砝码的重量+能计算出的重量)
    那么上述的过程就是一个从背包里取出东西的过程。
    在代码里有详细的分析。
背包正反各来一遍

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #define MAXN 2005
 7 using namespace std;
 8 int w[MAXN];
 9 bool dp[MAXN];//滚动数组,只要一维,内存优化
10 int main()
11 {
12     int t,n,q,k;
13     scanf("%d",&t);
14     while(t--)
15     {
16         scanf("%d",&n);
17         for(int i = 0;i<n;i++)
18         {
19             scanf("%d",&w[i]);
20         }
21         memset(dp,false,sizeof(dp));
22         dp[0] = true;
23         //positive
24         //正着来一次背包,按阶段每一次添加一个
25         for(int i = 0;i<n;i++)
26         {
27             //每一次选择当前这个砝码,j表示的是当前可以称出来的重量
28             //j-w[i]表示前一轮该重量是否有
29             for(int j = MAXN;j>=w[i];j--)
30             {
31                 dp[j]|=dp[j-w[i]];
32             }
33             
34             //必须倒着来,如果正着来错误!!
35             /*
36                   for(int j = 0;j<=MAXN-w[i];j++)
37                 {
38                     dp[j+w[i]]|=dp[j];
39                 }
40                 在这一次循环中用到了本轮已更新的结果,我们只能用前一轮的结果
41                 这样会出现的错误是一轮中加了n个w[i],而且在本轮中加了n个,毫无疑问!
42             */
43         }
44         
45         //negative
46         //逆着来一遍,从背包中取出东西
47         for(int i = 0;i<n;i++)
48         {
49             //按照我的题解就是每一次选中当前的这个砝码作为右端砝码
50             //j表示左端减去右端的重量
51             //也许你要理解的是每一次你只选一个,这样的话要是右端放多个不也行吗
52             //但是你要知道你每一轮的新重量其实是保留下来了(更新了)
53             //所以下一轮中用了前一个砝码的新重量你还可以用(也就是再减一个砝码)
54             for(int j = 0 ; j<=MAXN-w[i] ; j++)
55             {
56                 dp[j]|=dp[j+w[i]];
57             }
58             
59              //必须正着来,如果倒着来也错误!!
60             /*
61                   for(int j = MAXN-w[i];j>=0;j--)
62                 {
63                     dp[j-w[i]]|=dp[j];
64                 }
65                 在这一次循环中用到了本轮已更新的结果,我们只能用前一轮的结果
66                 这样会出现的错误是一轮中减了n个w[i],而且在本轮中减了n个,毫无疑问!
67             */
68         }
69         scanf("%d",&q);
70         for(int i = 1;i<=q;i++)
71         {
72             scanf("%d",&k);
73             if(dp[k])
74                 printf("YES\n");
75             else
76                 printf("NO\n");
77         }
78     }
79     return 0;
80 }

 

posted @ 2016-02-14 16:08  fancy_boy  阅读(609)  评论(0编辑  收藏  举报