动态规划-背包问题

0-1背包

解决思路:

每次尝试往背包里新加一个物品,如果装不下,则将体积组建增大。当能装下时候,用当前体积减去新装入的这个物品的体积,得到除了当前这个物品的体积,在之前的已知解中查找这个体积容纳的最大价值,用这个最大价值加上当前物品的价值就是新的最大价值。

#include<iostream>
#include<stdio.h>
using namespace std;

void Knapsack(int n,int c,int *w,int *p){
    int f[100][100];
    int i=0,j=0;
    for(i=1;i<=n;i++){  # n 是物品的个数,这一层循环尝试逐个添加物品
        for(j=1;j<=c;j++){  # j是当前体积,逐渐增加体积 ,观察体积变大后放入当前物品j之后价值的变化
            f[i][j]=f[i-1][j]; # i-1 是上一个物品, [j] 当前体积,f[i-1][j] 也就是上一个物品当前体积下的最大价值
            if(j>=w[i]){  # j 是当前体积, w[i] 是当前物品的体积,因为要往背包里放入当前物品,所以当前假定的体积要大于物品的体积
                f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+p[i]);  # 如果能放下,要查找除掉当前物品的体积之后的体积能装的最大的价值, f[i-1][*] 是添加上一个物品的已知解空间, 
                # w[i] 是当前物品的体积, j 是当前假设背包的体积 j-[w[i]] 也就是当前背包的体积去掉当前物品的体积, f[i-1][j-w[i]] 就是去掉当前物品体积后还剩下的体积装的最大价值
                # f[i-1][j-w[i]]+p[i] 即是装上当前物品后的最大价值
                # f[i-1][j] 是不转入当前物品的最大价值,一般不会取这个值,除非有物品价值为负数或者0
            }
        }
    }

    cout<<"背包能装的最大价值是:" << f[i-1][j-1] <<endl;
}
int main(){
    int n;
    int c;

    c=10;   //背包容量c
    n=5;    //物体个数n
    int w[6]={0,2,2,6,5,4};   //物品体积
    int p[6]={0,6,3,5,4,6};   //物品价值
    Knapsack(n,c,w,p);

}

分组背包

分组背包与01背包的区别是,分组背包需要在一组商品中只能选择一个。
一组商品中可以包含n个商品。在01背包中选择一个物品加入背包观察价值是否变化,在分组背包中,则是尝试将一组物品组个尝试加入背包,观察最大价值的是哪个。

分组背包时间复杂度:

\(O(n) = \sum\limits_{i=1}^{m} C*M[i]\)

参数 说明
C 容积
M[i] 第i个分组中物品的个数
m 分组个数

如果背包的体积为C,物品的个数为N,则算法复杂度为:

$ O(n) = C * N $

参考:

posted @ 2022-06-28 20:04  oaksharks  阅读(35)  评论(0编辑  收藏  举报