DP:Cow Exhibition(POJ 2184)(二维问题转01背包)

               

                  牛的展览会

  题目大意:Bessie要选一些牛参加展览,这些牛有两个属性,funness和smartness,现在要你求出怎么选,可以使所有牛的smartness和funness的最大,并且这两个和都不能为负值

  这一题很有意思,首先是这个问题是二维的,它包含两个属性,但是他有一个很重要的条件就是牛只能选一次,所以我们一开始就很容易想到用背包貌似可以求解,但是这一题没有办法直接用背包,因为没有直接给出价值和容量(他给了两个价值)。

  但是,我们稍微变换一下,这一题就可以做了,我们要把一个看成是价值,把另一个看成是容量(容量随着包(牛)的增加而增加,可以视为无限)。但是很不幸的是,这一题是有负值的,但是没有关系,因为这一题的两个价值都是有范围的,所以我们可以采用把背包的中点定在半个范围内就可以了(相当于+range/2),那么最终我们把一个在二维展开的问题(求横纵坐标的和的最大值)转化为了一维背包的问题,求解的过程是和01背包是一样的,在负值的时候稍微注意一下反转求解方向就可以了(但是这一题可以剪枝,等一下讲)。

  到目前为止我们先入为主讲明白了这一题可以用01背白做,但是为什么呢?其实我自己一开始做的时候是按照离散的思想把100个包按照f+s的大小从小到大排,然后想按照像3666那样做DP,但是这样是不行的,因为我们无法确定负值的时候是否放入包,这样就会很麻烦(其实我自己也不知道自己是怎么想的),那么在这一题,我为什么可以把f看成价值把s看成容量?其实我们把另一个看成价值也是没问题的,其实价值和容量是可以互换的,容量其实是无限的,我们只是把他的解的区间固定在一个位置上,然后相当于是定住一个量,来求另一个量的最大值,因为我们我们用的是背包,所以我们价值的那个量一定是完全求解的,题目要我们求最大值,所以我们只用求出价值的最大值,那么最优解一定在最后的全局解内出现。

  最后说一下裁枝的问题,我们可以看到,如果我们只用简单的背包去求,那么会浪费大量的时间在无用的背包赋值(比如在i=1的时候,1000以后的背包值根本不可能有意义),所以我们根据到第几个背包来逐步扩大范围,减少求解的范围,节约时间。

  

 1 #include <iostream>
 2 #include <functional>
 3 #include <algorithm>
 4 
 5 using namespace std;
 6 typedef struct _cows
 7 {
 8     int smart;
 9     int fun;
10 }Cows_Set;
11 
12 static Cows_Set cows[101];
13 static int dp[2 * 1000 * 100 + 10];
14 
15 void Search(const int);
16 
17 int main(void)
18 {
19     int n;
20     while (~scanf("%d", &n))
21     {
22         for (int i = 0; i < n; i++)
23             scanf("%d%d", &cows[i].smart, &cows[i].fun);
24         Search(n);
25     }
26     return 0;
27 }
28 
29 void Search(const int n)
30 {
31     //01背包处理二维情况,要把一个看成容量,另一个看成价值
32 
33     int root = n * 1000, max_range = root * 2 + 10, ans = 0xf0f0f0f0, tmp_max, tmp_min;
34     fill(dp, dp + max_range, 0xf0f0f0f0);
35 
36     dp[root] = 0;//01背包,就是把这个位置定为0,其他地方都是"不合法"
37 
38     for (int i = 0; i < n; i++)
39     {
40         tmp_max = root + i * 1000 + cows[i].smart;//对区间剪枝
41         tmp_min = root - i * 1000 + cows[i].smart;
42         if (cows[i].smart >= 0)
43         {
44             for (int j = tmp_max; j >= tmp_min; j--)
45                 dp[j] = max(dp[j], dp[j - cows[i].smart] + cows[i].fun);
46         }
47         else
48         {
49             for (int j = tmp_min; j <= tmp_max; j++)
50                 dp[j] = max(dp[j], dp[j - cows[i].smart] + cows[i].fun);
51         }
52     }
53 
54     for (int i = root; i < max_range; i++)
55         if (dp[i] >= 0)
56             ans = max(ans, i - root + dp[i]);
57 
58     printf("%d\n", ans);
59 }

posted @ 2015-11-12 23:54  PhiliAI  阅读(350)  评论(0编辑  收藏  举报