DP:Cow Exhibition(POJ 2184)(二维问题转01背包)
2015-11-12 23:54
441 查看
![](http://images2015.cnblogs.com/blog/798615/201511/798615-20151119221410593-1671499213.jpg)
牛的展览会
题目大意:Bessie要选一些牛参加展览,这些牛有两个属性,funness和smartness,现在要你求出怎么选,可以使所有牛的smartness和funness的最大,并且这两个和都不能为负值
这一题很有意思,首先是这个问题是二维的,它包含两个属性,但是他有一个很重要的条件就是牛只能选一次,所以我们一开始就很容易想到用背包貌似可以求解,但是这一题没有办法直接用背包,因为没有直接给出价值和容量(他给了两个价值)。
但是,我们稍微变换一下,这一题就可以做了,我们要把一个看成是价值,把另一个看成是容量(容量随着包(牛)的增加而增加,可以视为无限)。但是很不幸的是,这一题是有负值的,但是没有关系,因为这一题的两个价值都是有范围的,所以我们可以采用把背包的中点定在半个范围内就可以了(相当于+range/2),那么最终我们把一个在二维展开的问题(求横纵坐标的和的最大值)转化为了一维背包的问题,求解的过程是和01背包是一样的,在负值的时候稍微注意一下反转求解方向就可以了(但是这一题可以剪枝,等一下讲)。
到目前为止我们先入为主讲明白了这一题可以用01背白做,但是为什么呢?其实我自己一开始做的时候是按照离散的思想把100个包按照f+s的大小从小到大排,然后想按照像3666那样做DP,但是这样是不行的,因为我们无法确定负值的时候是否放入包,这样就会很麻烦(其实我自己也不知道自己是怎么想的),那么在这一题,我为什么可以把f看成价值把s看成容量?其实我们把另一个看成价值也是没问题的,其实价值和容量是可以互换的,容量其实是无限的,我们只是把他的解的区间固定在一个位置上,然后相当于是定住一个量,来求另一个量的最大值,因为我们我们用的是背包,所以我们价值的那个量一定是完全求解的,题目要我们求最大值,所以我们只用求出价值的最大值,那么最优解一定在最后的全局解内出现。
最后说一下裁枝的问题,我们可以看到,如果我们只用简单的背包去求,那么会浪费大量的时间在无用的背包赋值(比如在i=1的时候,1000以后的背包值根本不可能有意义),所以我们根据到第几个背包来逐步扩大范围,减少求解的范围,节约时间。
#include <iostream> #include <functional> #include <algorithm> using namespace std; typedef struct _cows { int smart; int fun; }Cows_Set; static Cows_Set cows[101]; static int dp[2 * 1000 * 100 + 10]; void Search(const int); int main(void) { int n; while (~scanf("%d", &n)) { for (int i = 0; i < n; i++) scanf("%d%d", &cows[i].smart, &cows[i].fun); Search(n); } return 0; } void Search(const int n) { //01背包处理二维情况,要把一个看成容量,另一个看成价值 int root = n * 1000, max_range = root * 2 + 10, ans = 0xf0f0f0f0, tmp_max, tmp_min; fill(dp, dp + max_range, 0xf0f0f0f0); dp[root] = 0;//01背包,就是把这个位置定为0,其他地方都是"不合法" for (int i = 0; i < n; i++) { tmp_max = root + i * 1000 + cows[i].smart;//对区间剪枝 tmp_min = root - i * 1000 + cows[i].smart; if (cows[i].smart >= 0) { for (int j = tmp_max; j >= tmp_min; j--) dp[j] = max(dp[j], dp[j - cows[i].smart] + cows[i].fun); } else { for (int j = tmp_min; j <= tmp_max; j++) dp[j] = max(dp[j], dp[j - cows[i].smart] + cows[i].fun); } } for (int i = root; i < max_range; i++) if (dp[i] >= 0) ans = max(ans, i - root + dp[i]); printf("%d\n", ans); }
![](http://images2015.cnblogs.com/blog/798615/201511/798615-20151119223006499-23617274.jpg)
相关文章推荐
- 解决IE6浮动元素产生的“双边距”BUG问题及解决办法
- C10K Problem
- 黑马程序员_JavaSe基础知识总结六:super、final关键字
- iOS -App主流框架UINavigationController && UITabBarController的简单使用
- 模拟实现printf
- 容器存储数据_迭代器JAVA112-115
- iOS -App主流框架UINavigationController && UITabBarController的简单使用
- Android笔记(五十七)Android总结:基础篇
- python小练习之换零钱
- Theano学习笔记(五)——配置设置与编译模型
- Theano学习笔记(四)——导数
- 嵌入式系统的含义
- Git笔记
- Java Base64加密、解密原理
- Theano学习笔记(三)——图结构
- 指针常量, 常量指针, 常量的指针常量
- hiho刷题日记——第十一天树中的最长路
- 简单几招,提高你的行动力
- Theano学习笔记(二)——逻辑回归函数解析
- 2015-11-11 hdu新生赛 F题(结束后一发AC)