用dp解决完全背包问题

//用二维dp解决完全背包问题(每种物品可以无限取,而不仅仅只有一个(物品同样不可分解))
//题目见书挑战程序设计竞赛p57完全背包问题:

//对于完全背包问题,和背包问题相比,我们一开始的考虑应该是在选择是否取物品的时候,背包问题我们
//只要考虑是取一件还是不取,而现在要考虑是取1-能取的最大件数和不取,所以第一思想我们要多加
//一重循环k,这个k用来遍历能取的件数,但是这么做会重复搜索许多的内容

//重复搜索的分析:在dp[i][j]的计算中选择k个的情况,与在dp[i][j-w[i]]的计算中选择k-1个的
//情况是相同的,所以你在dp[i][j]中搜索的选择取2-k个的情况,在dp[i][j-w[i]]的情况下已经搜索过了
//这样一直类推,其实每个物品要搜索的仍然还是只拿走一个物品的情况,其它情况都会由之前的dp搜索

//代码实现:
#include <bits/stdc++.h>
using namespace std;
const int MAX_N=100;
const int MAX_M=10000;
int n,w[MAX_N],v[MAX_N],W;
int dp[MAX_N+1][MAX_M+1];//此处i能达到的最大值为n(共n个物品),所以0-n共n+1个空间要开辟,j同理
int main() {
scanf("%d",&n);
for (int i=0;i<n;i++)
scanf("%d%d",&w[i],&v[i]);
scanf("%d",&W);
for (int i=0;i<n;i++) {//j<n!,因为dp[n][j]由dp[n-1][j]递推而来,没有dp[n+1][j]要递推
for (int j=0;j<=W;j++) {
if (j<w[i]) dp[i+1][j]=dp[i][j];
//因为这里可以重复取一样的物品,所以当取完这个物品后,不要跳过这个物品直接到前
//一个物品,应该继续保持在这个位置,看要不要再取
else dp[i+1][j]=max(dp[i][j],dp[i+1][j-w[i]]+v[i]);
}
}
printf("%d",dp[n][W]);

}

 

 

 

//一维dp解决背包问题(固定重量内尽可能装价值高的物品(物品不可分解)):
//题目见书挑战程序设计竞赛P57的背包问题

//与一维dp解决背包问题相比,解决完全背包问题,就是要对一个物品进行重复搜索,而要进行重复搜索
//我们只需要用到循环的继承性即可,所以在遍历dp时,我们从前往后进行遍历,这样前面的dp先遍历
//后面的dp就可以继承到前面dp的遍历结果,所以前面dp[1]对这个物品搜索过1次,拿走1个,那么dp[2]
//就可以判断再拿走一个,dp[2]自己拿了1次,再从dp[1]那继承了1次,所以最后dp[2]拿了2次,以此类推

//综述:在dp遍历时,从最前面能拿的那一个开始,遍历到最大的那个重量即可

//代码实现:
#include <bits/stdc++.h>
using namespace std;
const int MAX_N=100005;
int n,W;
int w[MAX_N],v[MAX_N];
int dp[MAX_N];
int main() {
scanf("%d",&n);
for (int i=0;i<n;i++) scanf("%d%d",&w[i],&v[i]);
scanf("%d",&W);
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",dp[W]);
return 0;
}

posted @ 2021-07-20 19:03  jue1e0  阅读(188)  评论(0)    收藏  举报