标签:循环 printf 直接 计算 01背包 white font 解决 选择
递推关系:
dp[0][j]=0
dp[i+1][j]=max{dp[i][j-k*w[i]]+k*v[i]|0<=k}
但直接这样去写程序是三重循环,时间复杂度为O(mW^2).
在这个算法中有多余的计算:
在dp[i+1][j]的计算中选择k(k>=1)个 i 物品的情况,与在dp[i+1][j-w[i]]的计算中选择k-1的情况是相同的,所以dp[i+1][j]的递推中k>=1部分的计算已经在dp[i+1][j-w[i]]的计算中完成了。那么可以按照如下方式进行变形:
dp[i+1][j]
=max{dp[i][j-k*w[i]]+k*v[i]|0<=k}
=max(dp[i][j],max{dp[i][j-k*w[i]]+k*v[i]|1<=k})
=max(dp[i][j],max{dp[i][(j-w[i])-k*w[i]]+k*v[i]|0<=k}+v[i])
=max(dp[i][j],dp[i+1][j-w[i]]+v[i])
这样一来就可以用O(nW)时间解决问题
?
void solve(){
for(int i = 0; i < n; i++){
for(int j = ;j <= W;j++){
if(j<W[i]){
????dp[i+1][j] = dp[i][j];
}else {
????dp[i+1][j] = dp[i+1][ j-w[i] ] + v[i] );
}
}
}
printf("%d\n", dp[n][W]);
?
使用了滚动数组,并且只是01背包代码的修改而已
回想一下我们学01背包滚动数组版本的时候,是不是要求数组第二维的j一定要从后往前,从大到小来遍历,就是为了防止新数据被新数据覆盖
我们只允许旧数据被新数据覆盖(拿一次还是不拿),那么新数据被新数据覆盖在实际层面怎么理解呢,就是(拿j次还是拿j-1次)
所以接下来我们在01背包代码的基础上让第二维的j从小到大,从前往后
如果说新数据覆盖新数据更好,那么我就给你覆盖,也就是如果已经拿了几个这种物品了,如果再拿几个会更好,那我就给你拿
01背包问题的情况
?
int dp[MAX_W+1];
?
void solve(){
????for(int i = 0; i < n; i++){
????for(int j = W; j >= w[i]; j--){
????dp[j] = max(dp[j], dp[ j – w[i]] + v[i]);
}
}
printf("%d\n", dp[W]);
}
?
01背包问题的情况
?
int dp[MAX_W+1];
?
void solve(){
????for(int i = 0; i < n; i++){
????for(int j = w[i]; j <= W; j++){
????dp[j] = max(dp[j], dp[ j – w[i]] + v[i]);
}
}
printf("%d\n", dp[W]);
}
标签:循环 printf 直接 计算 01背包 white font 解决 选择
原文地址:https://www.cnblogs.com/Pandapig/p/13375641.html