动态规划初步-完全背包问题
2016-10-25 17:56
204 查看
问题描述:
有n种重量和价值分别为wi,vi的物品。从这些物品中挑选总重量不超过m的物品,求出挑选物品价值总和的最大值。在这里,每种物品可以挑选任意多件。
限制条件:
1<=n<=100
1<=wi,vi<=100
1<=w<=10000
思路分析:
与之前的01背包问题相似(01背包问题链接),只是这里每件物品可供挑选的数量不限,因此首先想到的就是,在先前01背包问题的基础上,对第i件物品的数量进行讨论。
即:dp[i][j]=max{dp[i-1][j-k*w[i]]+k*v[i] | k>=0}
这里的k为第i件物品的件数,即分别讨论拿0,1,2,3……件i物品,取其中的最大值作为dp[i][j]的值。
代码实现上很容易想到加一层for循环。int DP()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int k=0;k*w[i]<=j;k++)
{
dp[i][j]=max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);
}
}
}
return dp
[m];
}
可是这样的程序构成了3层循环,最内层循环的最坏情况可能从0循环至m,所以这个算法的时间复杂度为O(n*m^2)。这样并不够好。
注意到dp[i][j]中计算k个的情况与在dp[i][j-w[i]]中计算k-1个一样,也就是进行了很多重复计算,从这个角度去寻找优化的方法。
dp[i][j]=max{dp[i-1][j-k*w[i]]+k*v[i] | k>=0}
=max(dp[i-1][j],max{dp[i-1][j-k*w[i]]+k*v[i] | k>=1})
=max(dp[i-1][j],max{dp[i-1][j-w[i]-k*w[i]]+k*v[i] | k>=0})//此处与第一行结构相同
=max(dp[i-1][j],dp[i][j-w[i]])
这样一来就不需要关于k的for循环了,便可以用O(n*m)时间解决问题。
代码实现:
#include"cstdio"
#include"algorithm"
using namespace std;
int n,m;
int w[105],v[105];
int dp[105][10005]={0};
int DP()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
/*
for(int k=0;k*w[i]<=j;k++)
{
dp[i][j]=max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);
}
*/
if(j<w[i])
dp[i][j]=dp[i-1][j];
else
dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+v[i]);
}
}
return dp
[m];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d%d",&w[i],&v[i]);
printf("%d\n",DP());
return 0;
}
/*
测试样例:
3 7
3 4
4 5
2 3
*/
有n种重量和价值分别为wi,vi的物品。从这些物品中挑选总重量不超过m的物品,求出挑选物品价值总和的最大值。在这里,每种物品可以挑选任意多件。
限制条件:
1<=n<=100
1<=wi,vi<=100
1<=w<=10000
思路分析:
与之前的01背包问题相似(01背包问题链接),只是这里每件物品可供挑选的数量不限,因此首先想到的就是,在先前01背包问题的基础上,对第i件物品的数量进行讨论。
即:dp[i][j]=max{dp[i-1][j-k*w[i]]+k*v[i] | k>=0}
这里的k为第i件物品的件数,即分别讨论拿0,1,2,3……件i物品,取其中的最大值作为dp[i][j]的值。
代码实现上很容易想到加一层for循环。int DP()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
for(int k=0;k*w[i]<=j;k++)
{
dp[i][j]=max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);
}
}
}
return dp
[m];
}
可是这样的程序构成了3层循环,最内层循环的最坏情况可能从0循环至m,所以这个算法的时间复杂度为O(n*m^2)。这样并不够好。
注意到dp[i][j]中计算k个的情况与在dp[i][j-w[i]]中计算k-1个一样,也就是进行了很多重复计算,从这个角度去寻找优化的方法。
dp[i][j]=max{dp[i-1][j-k*w[i]]+k*v[i] | k>=0}
=max(dp[i-1][j],max{dp[i-1][j-k*w[i]]+k*v[i] | k>=1})
=max(dp[i-1][j],max{dp[i-1][j-w[i]-k*w[i]]+k*v[i] | k>=0})//此处与第一行结构相同
=max(dp[i-1][j],dp[i][j-w[i]])
这样一来就不需要关于k的for循环了,便可以用O(n*m)时间解决问题。
代码实现:
#include"cstdio"
#include"algorithm"
using namespace std;
int n,m;
int w[105],v[105];
int dp[105][10005]={0};
int DP()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
/*
for(int k=0;k*w[i]<=j;k++)
{
dp[i][j]=max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);
}
*/
if(j<w[i])
dp[i][j]=dp[i-1][j];
else
dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+v[i]);
}
}
return dp
[m];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d%d",&w[i],&v[i]);
printf("%d\n",DP());
return 0;
}
/*
测试样例:
3 7
3 4
4 5
2 3
*/
相关文章推荐
- 动态规划:最少硬币找零问题、01背包问题、完全背包问题
- 动态规划之01背包、完全背包问题
- 动态规划-----背包问题-----01背包,完全背包,多重背包
- 动态规划-完全背包问题
- 动态规划之背包问题(二):完全背包问题
- 算法竞赛宝典 动态规划 货币系统问题(完全背包+一维优化)
- 完全背包问题动态规划c++
- 动态规划--背包问题(0-1背包,完全背包,多重背包)
- 动态规划-----背包问题-----01背包,完全背包,多重背包
- HDU 2159 FATE (动态规划dp之二维完全背包问题)
- 动态规划—完全背包问题
- 动态规划:完全背包问题-HDU1114-Piggy-Bank
- ACM:动态规划,物品无限的背包问题(完全背包问题)
- HDOJ 题目1284钱币兑换问题(动态规划,完全背包)
- 动态规划-完全背包问题
- 0-1背包问题的动态规划解法
- 动态规划:0-1背包问题(使用迭代方法,避免重复计算)
- 动态规划的两个经典问题--01背包
- 动态规划_背包问题扩展
- 动态规划解背包问题/C++/Knapsack problem