您的位置:首页 > 其它

POJ 2184 Cow Exhibition

2014-10-25 12:45 246 查看
这题看了网上的代码和题解才AC了。不过自己还是不太明白,背包这东西,线性规划这东西,看得我头疼,我光看别人的代码和题解就看了两个多小时,别人太牛逼,贴上代码,随便写了几句话就ok了,可是我真心不明白他们是怎么来的,怎么想的。我就简单的说说自己的理解吧,也好为自己以后再看的时候方便一点。其实自己现在对背包的理解还不是很透彻,只停留在模仿的阶段,并不能正真体会其中状态转移方程的内涵。

首先这题数据有正有负,最后还要求smart和fun的值都不小于0,当时自己真心一点思路都没有,最多就是想到把坐标平移一下,毕竟用数组保存数据的时候,下标不能是负的嘛!后来看了网上的题解,是把smart作为花费值,即背包中的cost;fun作为价值,即背包中的value。用01背包求出每个smart对应的最大的fun值,然后把smart和其对应的最大的fun值相加,再从中找出最大值,就是所求的结果。详细解释看代码中的注释。

#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=105;
//M值为什么是这个呢?题目中N<=100,-1000<=smart<=1000,所以最后范围为-1000*100~1000*100,
//又由于数组下标不能是负的,坐标整体平移,所以最后的结果就是这个值。
const int M=200005;
const int inf=-100000000;
int result[M],s[M],f[M];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
scanf("%d%d",&s[i],&f[i]);
//这里初始化的问题困扰了我好久,为什么这里初始化为inf。背包九讲中说如果是
//“恰好把背包装满”则初始化为inf,因为初始化result数组就是在没有任何物品
//可以放入背包时的合法状态,那么此时只有容量为0的背包可以在什么也不装且价
//值为0的情况下被“恰好装满”,其他的都是不合法的。可是这题说了“恰好把背包装满”吗?
//于是我就开始思考:假设smart的值为2和5,对应01背包的话就是两个物品,容量分别为2和5。
//那么最后只能存在0(什么都不装,即恰好装满容量为0的背包),2(恰好装满容量为2的背包),5,7这四个合法状态存在。
//其他的都不应该出现,都是不合法的,例如恰好装满容量为3的背包在这里是不可能实现的。也就是说这题的题意就是暗含
//“恰好把背包装满”的意思。如果是初始化为0,按照背包九讲就是“背包不一定要装满,
//只要价值最大”。显然这里是不适合的。
for(int i=0;i<=M;i++)
result[i]=inf;
//坐标原点移到100000,所以此时只有它是合法状态,初始化为0.
result[100000]=0;
for(int i=1;i<=n;i++)
{
//这里把s[i]分开讨论也让我纠结的不行,后来看了别人的题解,自己再仔细想想,终于明白了。
//我们都知道,01背包求解的过程中药避免重复计算。
//如果s[i]大于0显然从后往前扫,但是为什么s[i]小于0就要从前往后扫呢?
//设s[i]=-x(x为正值),则result[j-(-x)]=result[j+x],这样如果从后往前扫,
//若result[j]=result[j+x]+f[i],而此时result[j+x]由于从后往前扫已经计算出来,
//代表的是前i件物品放入容量为j+x的背包的最大价值,并不是前i-1件物品放入容量为j+x的背包的最大价值。
//而这是和01背包只能放入一次是相互矛盾的。
//只有从前往后扫,才能保证result[j+x]的值是前i-1件物品放入背包的最大价值。否则就会重复计算的。
if(s[i]>=0)
{
for(int j=M;j>=s[i];j--)
{
int temp=result[j-s[i]]+f[i];
if(result[j]<temp)
result[j]=temp;
}
}
else
{
for(int j=s[i];j<=M+s[i];j++)
{
int temp=result[j-s[i]]+f[i];
if(result[j]<temp)
result[j]=temp;
}
}
}
int max=inf;
//这里从100000开始遍历,是为了满足题目中的smart的值不小于0。
for(int i=100000;i<=M;i++)
{
//这里的判断是为了满足题目中的fun不小于0。
if(result[i]>=0)
{
int temp=i-100000+result[i];
if(max<temp)
max=temp;
}
}
printf("%d\n",max);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: