【01背包】
有N件物品和一个载重为W的背包。第i件物品的重量是
w[i]
,价值是
v[i]
。
求解背包最多能装下的价值是多少?
【解法一 动态规划】
思路分析:
对于每件物品,只有两种情况:装?不装?。
假设dp[i][j]表示在背包剩余载重j的情况下,前i个物品能达到的最大价值。
对于第i个物品,
如果w[i]>j,放不进去,不能放,故dp[i][j]=dp[i-1][j]
如果w[i]<=j,根据每种物品是否放入背包,有两种可能,
【1】不放 dp[i][j]=dp[i-1][j]
【2】放 dp[i][j]=dp[i-1][j-w[i]]+v[i]
取两者较大者即可
dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])
状态转移方程
dp[i][j]=dp[i-1][j] (w[i]>j)放不进
dp[i][j]=max (dp[i-1][j], dp[i-1][ j-w[i] ] +v[i])放和不放取较大的。
【实例】
下图是对本题的实际模拟。
初始状态
no items时,无论包载重多少,都装不了任何价值的东西,故dp[0][i]=0;
载重或capacity=0时,不能转任何重量的物品,故dp[i][0]=0;
后的dp[x][y]按状态转移方程,推出即可。可以手动填入数据理解算法原理。
附上在线模拟背包问题连接
0-1背包问题在线模拟网址
【附上代码】
#include<iostream>
#include<stdio.h>
using namespace std;
int n=5;
int w[6]={0,4, 6, 5, 7,3};
int v[6]={0,12,10,8,11,14};
int dp[6][17]={0};
int main()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=16;j++)
{
if(j<w[i])
{
dp[i][j]=dp[i-1][j];
}
else
{ //放进去
int temp=dp[i-1][j-w[i]]+v[i];
dp[i][j]=dp[i-1][j];
if(temp>dp[i][j])
dp[i][j]=temp;
}
}
}
for(int i=0;i<6;i++)
{
cout<<"item:"<<i<<" ";
for(int j=0;j<17;j++)
{
printf("%4d",dp[i][j]);
}
cout<<endl;
}
}
运行截图
【解法二 递归】
思路分析:
对于每种物品无非是两种状态 放 or 不放。用一个bool型的一维数组choose记录是否放入,用0 1 表示这两种状态,choose[i]=true,表示放入,choose[i]=false,表示第i件物品不放入。
对于第i个物品,当我们尝试了其中一种状态(true或false),便可以尝试是否放入下一个i+1 ,然后对i尝试另外一种状态。
当把所有的物品尝试完了后,便得到了一种组合情况,统计这种放入的组合情况是否超过背包载重以及是否大于已经记录的最大价值。
#include<iostream>
using namespace std;
int n=5;//物品数目
bool choose[6]={0};//记录是否装入;
bool res[6]={0};//记录当前最大价值时的装入情况。
int w[6]={0,4, 6, 5, 7,3};//重量
int v[6]={0,12,10,8,11,14};//价值
int maxw=16;//背包载重值
int maxv=0;//初始最大价值。
int sumw()//统计装入的重量
{
int total=0;
for(int i=1;i<=5;i++)
{
if(choose[i]==1)
{
total+=w[i];
}
}
return total;
}
int sumv()//统计装入的价值
{
int total=0;
for(int i=1;i<=5;i++)
{
if(choose[i]==1)
{
total+=v[i];
}
}
return total;
}
void dfs(int x)//递归,尝试将所有可能情况遍历,
{
if(x>n)
{
int tempw=sumw();
int tempv=sumv();
if(tempw<=maxw&&tempv>maxv)//装入重量在背包载重内,
//并且此时装入放背包的价值大于之前记录的最大价值
{
maxv=tempv;
for(int i=1;i<=5;i++)
{
res[i]=choose[i];
}
}
}
else
{
choose[x]=true;
dfs(x+1);
choose[x]=false;
dfs(x+1);
}
}
int main()
{
dfs(1);
cout<<"max value: "<<maxv<<endl;
for(int i=0;i<=5;i++)
{
if(res[i]==1)
{
cout<<"items: "<<i<<" W:"<<w[i]<<" V:"<<v[i]<<endl;
}
}
}
运行截图