一 问题描述:
有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
所谓01背包,表示每一个物品只有一个,要么装入,要么不装入。
二 解决方案:
考虑使用动态规划求解,定义一个递归式 opt[i][v] 表示前i个物品,在背包容量大小为v的情况下,最大的装载量。
opt[i][v] = max(opt[i-1][v] , opt[i-1][v-c[i]] + w[i])
解释如下:
opt[i-1][v] 表示第i件物品不装入背包中,而opt[i-1][v-c[i]] + w[i] 表示第i件物品装入背包中。
花费如下:
时间复杂度为O(V * N) ,空间复杂度为O(V * N)。时间复杂度已经无法优化,但是空间复杂度则可以进行优化。
有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
所谓01背包,表示每一个物品只有一个,要么装入,要么不装入。
二 解决方案:
考虑使用动态规划求解,定义一个递归式 opt[i][v] 表示前i个物品,在背包容量大小为v的情况下,最大的装载量。
opt[i][v] = max(opt[i-1][v] , opt[i-1][v-c[i]] + w[i])
解释如下:
opt[i-1][v] 表示第i件物品不装入背包中,而opt[i-1][v-c[i]] + w[i] 表示第i件物品装入背包中。
花费如下:
时间复杂度为O(V * N) ,空间复杂度为O(V * N)。时间复杂度已经无法优化,但是空间复杂度则可以进行优化。
但必须将V 递减的方式进行遍历,即V.......0 的方式进行(其实可以V....c[i])。
knapsack:
1:只装入1个物品,确定在各种不同载重量的背包下,能够得到的最大价值
2:装入2个物品,确定在各种不同载重量的背包下,能够得到的最大价值
。。。
n:以此类推,装入n个物品,确定在各种不同载重量的背包下,能够得到的最大价值
printMaxValue:
确定装入背包的具体物品,从opt[n][m]向前逆推:
若opt[n][m]>opt[n-1][m],则第n个物品被装入背包,且前n-1个物品被装入载重量为m-w[n]的背包中
否则,第n个物品没有装入背包,且前n-1个物品被装入载重量为m的背包中
以此类推,直到确定第一个物品是否被装入背包为止
使用二维数组opt求解:
#include<iostream>
#define MAX 20
#define max(a,b) a>b?a:b
using namespace std;
int N,V;//物品数量和容量
int cost[MAX]; //费用
int value[MAX]; //价值
int opt[MAX][MAX]; //存放最大价值
int x[MAX];//x[i]为1表示第i个物品放入背包
int knapsack()//参数是物品数量和容量,X数组表示组成,F[N][V]表示最大价值
{
memset(opt,0,sizeof(opt));//初始化opt为0
for(int i=1;i<=N;i++)//求最大价值
{
for (int j=1;j<=V;j++)
{
if (cost[i]<=j)
opt[i][j]=max(value[i]+opt[i-1][j-cost[i]],opt[i-1][j]);
else
opt[i][j]=opt[i-1][j];
}
}
return opt[N][V];//返回最大值
}
void printMaxValue()//输出opt中的值(本函数无实际作用,只是为了显示下数据)
{
for(int i=0;i<=N;i++)
{
for(int j=0;j<=V;j++)
cout<<opt[i][j]<<" ";
cout<<endl;
}
}
void traceback()//输出放入背包的物品编号
{
for(int i=N;i>0;i--)//x[i]为1表示第i个物品放入背包
{
if(opt[i][V]==opt[i-1][V])
x[i]=0;
else
{
x[i]=1;
V-=cost[i];
}
}
for(int i=0;i<=N;i++)
if(x[i]) cout<<i<<" ";
}
int main()
{
while(cin>>N>>V)//输入物品数量和背包容量
{
for(int i=1;i<=N;i++)
cin>>cost[i]>>value[i];
cout<<"max="<<knapsack2()<<endl;
printMaxValue();
traceback();
cout<<endl;
}
return 0;
}

优化空间复杂度为O(V),使用一维数组:
#include<iostream>
#define MAX 20
using namespace std;
int N,V;//物品数量和容量
int cost[MAX]; //费用
int value[MAX]; //价值
int opt[MAX]; //存放价值
int knapsack() //参数是物品数量和容量,X数组表示组成,F[N][V]表示最大价值
{
memset(opt,0,sizeof(opt));//初始化opt为0
for(int i=1;i<=N;i++)//求最大价值
{
for (int j=V;j>=cost[i];j--)
{
if (value[i]+opt[j-cost[i]]>opt[j])
opt[j]=value[i]+opt[j-cost[i]];
}
}
return opt[V];//返回最大值
}
int main()
{
while(cin>>N>>V)//输入物品数量和背包容量
{
for(int i=1;i<=N;i++)
cin>>cost[i]>>value[i];
cout<<"max="<<knapsack()<<endl;
}
return 0;
}
参考 http://www.cppblog.com/jake1036/archive/2011/06/27/149566.html

本文详细阐述了利用动态规划解决01背包问题的方法,包括递归式定义、时间与空间复杂度分析,以及如何通过逆推确定最优装载方案。通过实例代码展示了解决过程,最终实现优化空间复杂度的动态规划算法。
3524

被折叠的 条评论
为什么被折叠?



