先看暴力求解,与01背包问题的区别就在于每个物品可以拿无限次,因此只需在此基础上加入一个次数的循环与判断即可,
#include<iostream>
using namespace std;
int main(){
int v[100];
int w[100];
int m,n;
cin>>m>>n;
for(int i=1;i<=m;i++)
{
cin>>v[i]>>w[i];
}
int arr[100][100];
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
for(int k=0;k*v[i]<=j;k++)
{
arr[i-1][j]=max(arr[i][j],arr[i-1][j-k*v[i]]+k*w[i]);
}
}
}
cout<<arr[m][n];
return 0;
}
上述算法时间复杂度太高为O(n^3),浪费时间,进行时间上的优化。
#include<iostream>
using namespace std;
int main(){
int v[100];
int w[100];
int m,n;
cin>>m>>n;
for(int i=1;i<=m;i++)
{
cin>>v[i]>>w[i];
}
int arr[100][100];
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
//如果装不下,则需要继承上层的最大价值,
//如果装不下,则需要进行比较上层的最大价值。
//故总结为无论如何都需要进行继承上层的最大价值。
arr[i][j]=arr[i-1][j];
if(j>=v[i])
{
//由于继承了上层的所以内部比较的前者为本身,
//内部比较的后者进行在本层基础上进行更新便可以完成循环的意义。
arr[i][j]=max(arr[i][j],arr[i][j-v[i]]+w[i]);
}
}
}
cout<<arr[m][n];
return 0;
}
根据上述的状态转移方程与01背包问题进行比较,则可以发现存在相似之处,且完全背包的状态转移方程也在两层之间进行比较,故也可利用滚动数组进行空间上的简化,
#include<iostream>
using namespace std;
int main(){
int v;
int w;
int m,n;
int arr[100]={0};
cin>>m>>n;
//添加进行边输入边运算
for(int i=1;i<=m;i++)
{
//故只需要一个变量存储
cin>>v>>w;
//将判断条件融合,因为即使不满足的也只是向下继承
for(int j=v;j<=n;j++)
{
//当前层的最大价值等于前一层的最大价值和修改后的最大价值的较大值
arr[j]=max(arr[j],arr[j-v]+w);
}
}
cout<<arr[n];
return 0;
}