01背包问题
问题描述
有N件物品和一个容量为C的背包。第i件物品的体积是c[i],价值是v[i]。求解将哪些物品装入背包可使价值总和最大。
分析
用动态规划算法,状态转移方程:dp[i][j]=max{dp[i-1][j],dp[i-1][j-c[i]]+v[i]}
其中,dp[i-1][j]表示第i件物品不装入背包中,而dp[i-1][j-c[i]]+v[i]表示第i件物品装入背包中。
时间复杂度为O(C*N) ,空间复杂度为O(C*N) 。 时间复杂度已经无法优化,但是空间复杂度则可以优化为O(C),因为每次只是用到了上一步中的两个值,
将V(也就是j)递减的方式进行遍历,即V.......0 的方式进行即可节省空间,重复利用。
初始化
若要求背包必须放满,则初始如下:f[0] = 0 , f[1...V]表示-INF。表示当容积为0时,只接受一个容积为0的物品入包。
若要求背包可以空下,则初始化如下:
f[0...V] = 0 ,表示任意容积的背包都有一个有效解即为0。
具体解释如下:
初始化的f数组事实上就是在没有任何物品可以放入背包时的合法状态。
如果要求背包恰好装满,那么此时只有容量为0的背包可能被价值为0的nothing“恰好装满”,
其它容量的背包均没有合法的解,属于未定义的状态,它们的值就都应该是-∞了。
如果背包并非必须被装满,那么任何容量的背包都有一个合法解“什么都不装”,
这个解的价值为0,所以初始时状态的值也就全部为0了。
代码
未对空间复杂度进行优化:
#include<iostream>
#include<cstdlib>
#include <cstring>
#define max(a,b) a>b?a:b
using namespace std;
int main()
{
int C,N;//total cost,total num
cin>>C>>N;
int** dp=(int **)malloc((N+1)*sizeof(int *));
dp[0]=(int *)malloc((C+1)*(N+1)*sizeof(int));
for(int i=1;i<=N;i++)
dp[i]=dp[i-1]+(C+1);
//http://03071344.lofter.com/post/10871e_34cade
int* c=(int *)malloc((N+1)*sizeof(int));//cost of each staff
int* v=(int *)malloc((N+1)*sizeof(int));//value of each staff
for(int i=1;i<=N;i++)
cin>>c[i]>>v[i];
memset(dp[0],0,sizeof(dp[0]));
for(int i=1;i<=N;i++)//each staff
{
for(int j=0;j<=C;j++)//cost
{
if(j>=c[i])
dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+v[i]);
else
dp[i][j]=dp[i-1][j];
//show the dp table
cout<<dp[i][j]<<" ";
}
cout<<endl;
}
cout<<dp[N][C]<<endl;
free(v);
free(c);
free(dp[0]);
free(dp);
return 0;
}
进行空间复杂度优化:
#include<iostream>
#include<cstdlib>
#include <cstring>
#define max(a,b) a>b?a:b
using namespace std;
int main()
{
int C,N;//total cost,total num
cin>>C>>N;
int* dp=(int *)malloc((C+1)*sizeof(int));
int* c=(int *)malloc((N+1)*sizeof(int));//cost of each staff
int* v=(int *)malloc((N+1)*sizeof(int));//value of each staff
for(int i=1;i<=N;i++)
cin>>c[i]>>v[i];
memset(dp,0,sizeof(dp));
for(int i=1;i<=N;i++)//each staff
{
for(int j=C;j>=0;j--)//cost,from max to min
{
if(j>=c[i])
dp[j]=max(dp[j],dp[j-c[i]]+v[i]);
//show the dp table in real order
cout<<dp[C-j]<<" ";
}
cout<<endl;
}
cout<<dp[C]<<endl;
free(v);
free(c);
free(dp);
return 0;
}