标签:
首先是自由评述:这几天的背包问题
0 1包:逆序。结果由上一组元素刷过去的结果得来的。
1 void ZeroOnePack(int val,int vol) 2 { 3 4 int i; 5 for(i=V;i>=vol;i--) 6 { 7 if(dp[i-vol]+val>dp[i]) 8 { 9 dp[i] = dp[i-vol]+val; 10 } 11 } 12 }
满 包:初始化的时候。这个有个好方法 -inf 其中const int inf = 1<<28-1;这样的。写在顶部
结果符合的得重新附值。 dp[0]=0常见的。
原理:明确的是这个值要足够小或者大。能导致过滤掉这个结果。
可以用这个来做 至多和至少问题。已经必须放入多少个的问题。
我想法是弄成二维的 然后至少往上搜。至多往下搜。已经必须放入多少的直接在这一层搜索。
完全背包:顺序。注意这个复杂度只有N*V了。因为不是一个物品刷一层循环 而是一种物品刷一层循环。并不能用01包的原理去单纯解释。
1 void ZeroOnePack(int val,int vol) 2 { 3 4 int i; 5 for(i=vol;i<=V;i+) 6 { 7 if(dp[i-vol]+val>dp[i]) 8 { 9 dp[i] = dp[i-vol]+val; 10 } 11 } 12 }
多重背包:如果说是利用完全包的刷一层方法。并不好知道你的个数使用了多少来维护个数!。所以分完全包的情况vol*num>=V 也就是说在这个范围内你 可以随意数量放置。(当然拉。必须是最优的。)而如果小于这个值 就用01包。 但是是用bin优化过的再进行01包。 这个时候是顺序还是逆序 呢?是顺序的。理解可以用01包去里面。当初错误理解完全包的方法可以在这里得到好的解释。所以用一个变量k=1 来进行。最后还得进行一次 num的01至于为什么 这个和bin 有关
1 void MulPack(int val,int vol,int num) 2 { 3 if(val*num>=aver) 4 { 5 ComPack(val,vol); 6 return; 7 } 8 9 int k=1; 10 while(k<num) 11 { 12 ZeroOnePack(k*val,k*vol); 13 14 num -= k; 15 k *= 2; 16 } 17 ZeroOnePack(num*val,num*vol); 18 }
混合背包:这种背包并不难,只要传入方式正确。以及注意满包问题。
1 int max(int a,int b) 2 { 3 return a>b?a:b; 4 } 5 void OneZeroPack(int val,int vol) 6 { 7 int j; 8 for(j=V;j>=vol;j--) 9 { 10 dp[j] = max(dp[j],dp[j-vol]+val); 11 } 12 } 13 void ComPack(int val,int vol) 14 { 15 int j; 16 for(j=vol;j<=V;j++) 17 { 18 dp[j] = max(dp[j],dp[j-vol]+val); 19 } 20 } 21 void MulPack(int val,int vol,int num) 22 { 23 if(val*num>=V) 24 { 25 ComPack(val,vol); 26 return; 27 } 28 int k = 1; 29 while(k<num) 30 { 31 OneZeroPack(val,vol); 32 num -= k; 33 k *= 2; 34 } 35 OneZeroPack(val,vol); 36 }
二维费用:说白了是添加一个数组。多一层循环。实际上经常和满包之类的在一起。这个时候注意初始化即可。另外,二维费用经常出现的是数目的限制。
必须放入指定M个数目。这个时候往往就是满包问题了。状态划分也得注意其含义的变化了。其实如果没有这类问题。那个数目限制还有什么意 义啊!。也对。其实我们是为了满足条件才使用的二维。然后状态方程使用来源法即可。
标签:
原文地址:http://www.cnblogs.com/Milkor/p/4250461.html