01背包问题--动态规划

问题描述

有n个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?

例如,有4件物品,背包可装物品的最大容量(bagv)为8,物品的容量和价值分别为2 3,3 4,4 5,5 6
用w代表物品的容量,用v代表物品的价值,如下表:

i(物品编号) 1 2 3 4
w(物品容量) 2 3 4 5
v(物品价值) 3 4 5 6

动态规划的核心就是填表,众多数据只需计算一次,保存表中,因此可以提高效率。
判断第i件物品可否放的下,就得考虑此时的j(当前背包状态)是否比w(i)要大。
找出递推关系式

  • 若j<=w(i)(放不下):这时当下状态即为前一次的状态dp[i][j]=dp[i-1][j]
  • 若j>=w(i)(放得下):此时需考虑放不放该物品两种选择的最优选择。
    (1)若不放,dp[i][j]=dp[i-1][j]
    (2)若放,dp[i][j]=dp[i-1][j-w[i]]+v[i]
    即此时应:max(dp[i][j]=dp[i-1][j],dp[i][j]=dp[i-1][j-w[i]]+v[i])
    有了这样的思想和关系式,就可以写出代码了
    代码实现
#include <iostream>
using namespace std;
int main()
{
    
    
int maxn=0,n,bagv,i,j,w[500],v[500],dp[20][20]={
    
    {
    
    0}};
 cin>>n>>bagv;
 for(i=1;i<=n;i++)
 {
    
    
  cin>>w[i]>>v[i];
 }
 for(i=1;i<=n;i++)
 {
    
    
  for(j=1;j<=bagv;j++)
  {
    
    
   if(w[i]>j)
   {
    
    
    dp[i][j]=dp[i-1][j];
   }
   else {
    
    
    dp[i][j]=max(dp[i-1][j-w[i]]+v[i],dp[i-1][j]);
    if(dp[i][j]>maxn)
    {
    
    
     maxn=dp[i][j];
    }
   }
  }
 }
 for(i=0;i<=n;i++)
 {
    
    
  for(j=0;j<=bagv;j++)
  cout<<dp[i][j]<<" ";//打印表格
  cout<<endl;
 }
cout<<maxn<<endl;
return 0;
}

背包问题最优解回溯
若想知道具体背包内最优条件下放了哪些东西,就可以通过回溯,通过同样的递推关系逆着查找判断.

  • 如果dp[i][j]==dp[i-1][j],即第i个没有放入背包,再去查看上一个(i-1)
  • 如果dp[i][j]==dp[i-1][j-w[i]]+v[i],即第i个放入了背包,标记此时的i,再去查看上一个(i-1)
    直至i=1全部都经过判断

代码实现

#include <iostream>
using namespace std;
int item[20]={
    
    0};
int maxn=0,n,bagv,i,j,w[500],v[500],dp[20][20]={
    
    {
    
    0}};
void findwhat(int i,int j)
{
    
    
 if(i>=1)
 {
    
    
  if(dp[i][j]==dp[i-1][j])//判断i放了没
  {
    
    
   item[i]=0;
   findwhat(i-1,j);
  }
  else if(j>=w[i]&&dp[i][j]==dp[i-1][j-w[i]]+v[i])
  {
    
    
   item[i]=1;
   findwhat(i-1,j-w[i]);
  }
 }
}
int main()
{
    
    
 cin>>n>>bagv;
 for(i=1;i<=n;i++)
 {
    
    
  cin>>w[i]>>v[i];
 }
 for(i=1;i<=n;i++)
 {
    
    
  for(j=1;j<=bagv;j++)
  {
    
    
   if(w[i]>j)
   {
    
    
    dp[i][j]=dp[i-1][j];
   }
   else {
    
    
    dp[i][j]=max(dp[i-1][j-w[i]]+v[i],dp[i-1][j]);
    if(dp[i][j]>maxn)
    {
    
    
     maxn=dp[i][j];
    }
   }
  }
 }
 for(i=0;i<=n;i++)
 {
    
    
  for(j=0;j<=bagv;j++)
  cout<<dp[i][j]<<" ";
  cout<<endl;
 }
 cout<<maxn<<endl;
 findwhat(n,bagv);
 for(i=1;i<=n;i++)
  if(item[i]==1)
  cout<<i<<" ";
 cout<<endl;
 return 0;
}

猜你喜欢

转载自blog.csdn.net/HT24k/article/details/105816968