问题描述
有n个物品,它们有各自的体积ci和价值wi,现有给定容量的背包v,如何让背包里装入的物品具有最大的价值总和?
原理:
动态规划与分治法类似,都是把大问题拆分成小问题,通过寻找大问题与小问题的递推关系,解决一个个小问题,最终达到解决原问题的效果。但不同的是,分治法在子问题和子子问题等上被重复计算了很多次,而动态规划则具有记忆性,通过填写表把所有已经解决的子问题答案纪录下来,在新问题里需要用到的子问题可以直接提取,避免了重复计算,从而节约了时间,所以在问题满足最优性原理之后,用动态规划解决问题的核心就在于填表,表填写完毕,最优解也就找到。
思路:
i为遍历的每一个物品,j为遍历0到v的体积,如果可以装下,由于装下不一定使总和最大,则装下即为dp[i-1][j-c[i]]+w[i],不装为dp[i-1][j],取两者中较大者。j-c[i]表示为目前物品空出空间,剩下的空间的价值取 之前可用空间下的最大值。
由此可以得出递推关系式:
1) j<c(i) dp(i,j)=dp(i-1,j)
2) j>=c(i) dp(i,j)=max{ dp(i-1,j),dp(i-1,j-c(i))+w(i) }
输入:
5 10
2 1
3 5
2 5
3 4
4 3
输出:
9
#include <stdio.h> #include <iostream> #include <math.h> #include <string.h> #include <algorithm> using namespace std; const double PI=acos(-1.0); const int inf=0x7fffffff; int w[105],c[105]; int dp[105][1000]; int n,v,mx,sum; int main(){ cin>>n>>v; for(int i=1;i<=n;i++){ cin>>w[i]>>c[i]; } for(int i=1;i<=n;i++){ for(int j=0;j<=v;j++){ if(j>=c[i]){ dp[i][j]=max(dp[i-1][j-c[i]]+w[i],dp[i-1][j]);//结果取选改物品和不选改物品价值的最大值 } else{ dp[i][j]=dp[i-1][j]; //空间不够,结果为之前的最大值 } } } cout<<dp[n][v]; return 0; }
节约空间写法:
#include <cstdio> #include <string.h> #include <iostream> #include <algorithm> #include <math.h> using namespace std; const int inf=0x7fffffff; const long long mod=1e9+7; const double PI=acos(-1); int w[105],c[105]; int dp[105]; int main() { int n,v; cin>>n>>v; for(int i=0;i<n;i++){ cin>>w[i]>>c[i]; } for(int i=0;i<n;i++){ for(int j=v;j>=c[i];j--){ dp[j]=max(dp[j-c[i]]+w[i],dp[j]); } } cout<<dp[v]; return 0; }