poj 2184 01背包变形:体积为负数的处理
2014-01-20 15:31
561 查看
今天遇到一题poj2184,大概思路是01背包dp之后把符合要求的最优解统计出来。但是在解01背包的时候遇到一个问题是体积有负数,这样在dp的过程中会遇到两个问题:循环的时候超出体积的范围;压缩空间的时候状态转移方程:dp[v]=max(dp[v],dp[v-c[i]]+w[i]),c[i]为负数时v-c[i]>v,这样按一般的循环的方向从大到下会重复计算。
先看第二个问题,在一般的01背包压缩空间的时候,体积的遍历是从大到小,因为dp[v]=max(dp[v],dp[v-c[i]]+w[i]),当前的dp[v]只取决于比自己小的dp[v-c[i]],所以从大到小遍历时每次dp[v-c[i]]和dp[v]都是上一次的状态。
如果体积为负v-c[i]>v,从大到小遍历dp[v-c[i]]是当前物品的状态,不是上一个,这样就会出错,解决的办法是从小到大遍历。
针对第一个问题,在处理的时候将整个数轴平移,使得原来所有可能的情况都为正。
例如这题,首先计算出数据的范围:
一共100组数,从-1000到1000,那么体积的范围就是-100*1000到100*1000。平移之后我们要处理的数据范围就在0到200000,新的原点变成100000。
初始化变成:
[cpp] view
plaincopy
for(int i=0;i<=200000;i++) dp[i]=-INF;
dp[100000]=0;
循环变成:
[cpp] view
plaincopy
for(int i=1;i<=n;i++)
{
if(s[i]>0)
{
for(int v=200000;v>=s[i];v--)
//从可能的最大值到最小值
{
if (dp[v-s[i]]>-INF)
dp[v]=max(dp[v],dp[v-s[i]]+f[i]);
}
}
else
{
for(int v=0;v-s[i]<=200000;v++)
{
if (dp[v-s[i]]>-INF)
dp[v]=max(dp[v],dp[v-s[i]]+f[i]);
}
}
}
计算结果要从100000开始遍历,因为100000相当于原来的0
[cpp] view
plaincopy
int nMax=0;
for(int v=100000;v<=200000;v++)
if(dp[v]>=0)
nMax=max(nMax,dp[v]+v-100000);
这题还有一种解决方法:把物品的体积全部加1000,使它们都大于0,然后dp的时候用一个数组记录dp[i][v]时多加了几个1000,最后在结果里减去就行了。这个做法有个需要注意的地方是状态转移变成:
而不是
[cpp] view
plaincopy
if(dp[v]<dp[v-s[i]]+f[i])
{
dp[v]=dp[v-s[i]]+f[i];
tot[v]=tot[v-s[i]]+1;
}
因为这时的最大值是某个v+dp[v]-tot[v]*1000,v一定的情况下dp[v]-tot[v]*1000表示的才是最大值,虽然这个最大值的意义不好理解。。
这题的第二种解法只是看结题报告粗浅的理解下,动态规划真是非常神奇。。。。
原文来自:
http://blog.csdn.net/actangy/article/details/7433992
致谢~~~~~~!
先看第二个问题,在一般的01背包压缩空间的时候,体积的遍历是从大到小,因为dp[v]=max(dp[v],dp[v-c[i]]+w[i]),当前的dp[v]只取决于比自己小的dp[v-c[i]],所以从大到小遍历时每次dp[v-c[i]]和dp[v]都是上一次的状态。
如果体积为负v-c[i]>v,从大到小遍历dp[v-c[i]]是当前物品的状态,不是上一个,这样就会出错,解决的办法是从小到大遍历。
针对第一个问题,在处理的时候将整个数轴平移,使得原来所有可能的情况都为正。
例如这题,首先计算出数据的范围:
一共100组数,从-1000到1000,那么体积的范围就是-100*1000到100*1000。平移之后我们要处理的数据范围就在0到200000,新的原点变成100000。
初始化变成:
[cpp] view
plaincopy
for(int i=0;i<=200000;i++) dp[i]=-INF;
dp[100000]=0;
循环变成:
[cpp] view
plaincopy
for(int i=1;i<=n;i++)
{
if(s[i]>0)
{
for(int v=200000;v>=s[i];v--)
//从可能的最大值到最小值
{
if (dp[v-s[i]]>-INF)
dp[v]=max(dp[v],dp[v-s[i]]+f[i]);
}
}
else
{
for(int v=0;v-s[i]<=200000;v++)
{
if (dp[v-s[i]]>-INF)
dp[v]=max(dp[v],dp[v-s[i]]+f[i]);
}
}
}
计算结果要从100000开始遍历,因为100000相当于原来的0
[cpp] view
plaincopy
int nMax=0;
for(int v=100000;v<=200000;v++)
if(dp[v]>=0)
nMax=max(nMax,dp[v]+v-100000);
这题还有一种解决方法:把物品的体积全部加1000,使它们都大于0,然后dp的时候用一个数组记录dp[i][v]时多加了几个1000,最后在结果里减去就行了。这个做法有个需要注意的地方是状态转移变成:
for(int i=1;i<=n;i++) for(int v=sum;v>=s[i];v--)//tot记录多加的1000 if(dp[v]-tot[v]*1000 < dp[v-s[i]]+f[i]-(1+tot[v-s[i]])*1000) { dp[v]=dp[v-s[i]]+f[i]; tot[v]=tot[v-s[i]]+1; }
而不是
[cpp] view
plaincopy
if(dp[v]<dp[v-s[i]]+f[i])
{
dp[v]=dp[v-s[i]]+f[i];
tot[v]=tot[v-s[i]]+1;
}
因为这时的最大值是某个v+dp[v]-tot[v]*1000,v一定的情况下dp[v]-tot[v]*1000表示的才是最大值,虽然这个最大值的意义不好理解。。
这题的第二种解法只是看结题报告粗浅的理解下,动态规划真是非常神奇。。。。
原文来自:
http://blog.csdn.net/actangy/article/details/7433992
致谢~~~~~~!
相关文章推荐
- POJ 2184 Cow Exhibition(01背包升级版+负数下标处理)
- POJ 2184 Cow Exhibition (体积为负时01背包的处理+问题转化)
- POJ-2184 Cow Exhibition(01背包变形)
- poj 2184 Cow Exhibition(dp之01背包变形)
- POJ 2184 Cow Exhibition (01背包变形 + 技巧 好题)
- POJ-2184 Cow Exhibition(01背包变形)
- poj 2184 Cow Exhibition 01背包变形,正负背包
- POJ - 2184 (01背包变形)
- POJ 2184 Cow Exhibition (01背包的变形)
- poj 2184 Cow Exhibition 01背包变形
- POJ 2184 Cow Exhibition 01 背包变形
- POJ 2184 Cow Exhibition (01背包变形)(或者搜索)
- POJ 2184 Cow Exhibition 奶牛展(01背包,变形)
- poj2184-01背包变形(正负背包)
- poj(2184)——Cow Exhibition(01背包变形)
- POJ-2184-01背包变形-Cow Exhibition
- POJ 2184 Cow Exhibition ( 01背包变形 )
- POJ 2184 Cow Exhibition(01背包变形)
- POJ-2184-01背包变形
- poj 2184 01背包变形