三种基本背包问题

一、0/1背包问题

问题描述:有n件物品和容量为m的背包 给出i件物品的重量以及价值 求解让装入背包的物品重量不超过背包容量 且价值最大 。
特点:这是最简单的背包问题,特点是每个物品只有一件供你选择放还是不放。如果想不通代码就填表观察过程。

 

输入:

5 10
2 6
2 3
6 5
5 4
4 6

输出:

15

  

 

① 二维解法
设f[i][j]表示前 i 件物品 总重量不超过 j 的最大价值 可得出状态转移方程

f[i][j]=max{f[i-1][j-a[i]]+b[i], f[i-1][j]}

核心代码

    
int f[100][100]={0}; 
for(int i=1;i<=num;i++){ for(int j=capacity;j>=1;j--){ if(weight[i]<=j) {f[i][j]=max(f[i-1][j],f[i-1][j-weight[i]]+value[i]);} else f[i][j]=f[i-1][j]; } }

表格:

 

 

②一维解法
设f[j]表示重量不超过j公斤的最大价值 可得出状态转移方程

f[j]=max{f[j], f[j−a[i]]+b[i]}

核心代码

    
int f[1000]={0};
for(int i=1;i<=num;i++){ for(int j=capacity;j>=weight[i];j--){ f[j]=max( f[j],f[j-weight[i]]+value[i] ); } }

循环的第二层

为什么要从后往前循环!!!!
      因为吧,从后往前循环,每次取得状态不会和你之前取得状态重合,这样就符合01背包的要求,每种物品只取一次;不理解填表

表格:

 完整代码:

#include <bits/stdc++.h>
using namespace std;
int main(){
    int num,capacity;   // 第一行为n值和c值,表示n件物品和背包容量c
    cin>>num>>capacity;
    int weight[1000];
    int value[1000];
    for(int i=1;i<=num;i++){  //每行有两个数据,分别表示第i(1≤i≤n)件物品的重量和价值。
        cin>>weight[i]>>value[i];
    }
    
    int f[1000]={0}; //设f[j]表示重量不超过j公斤的最大价值 可得出状态转移方程f[j]=max{f[j], f[j-a[i]]+b[i]}
    for(int i=1;i<=num;i++){
        for(int j=capacity;j>=weight[i];j--){
            f[j]=max( f[j],f[j-weight[i]]+value[i] );
        }
    }
     
    cout<<f[capacity]<<endl;
    return 0;
}

 

 

 

二、完全背包问题

问题描述:有n件物品和容量为m的背包 给出i件物品的重量以及价值 求解让装入背包的物品重量不超过背包容量 且价值最大 。
特点:题干看似与01一样 但它的特点是每个物品可以无限选用

设f[j]表示重量不超过j公斤的最大价值 可得出状态转移方程

f[j] = maxj{f[j], f[j−a[i]]+b[i]}

核心代码

    int f[1000]={0};
    for(int i=1;i<=num;i++){
        for(int j=weight[i];j<=capacity;j++){
            f[j]=max( f[j],f[j-weight[i]]+value[i] );
        }
    }

循环的二层

从前往后循环,每次取到的状态都会和前面的状态或多或少都有重叠,这样就刚好的满足了,每种物品无限取得要求了。

posted @ 2020-11-11 14:13  吹梦西洲  阅读(283)  评论(1编辑  收藏  举报