0/1背包问题

本文介绍了0/1背包问题的基本思想,它是动态规划的经典问题。内容包括问题描述、数据结构、解题过程图解,并提供了递归和递推两种算法源代码,帮助理解如何在有限体积的背包中选择物品以最大化价值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、0/1背包问题算法基本思想

0/1背包问题是经典的动态规划问题。

问题基本描述为:给你体积为V的背包,在物品G1,G2,G3...(这些物品所对应的体积分别为W1,W2,W3...价值分别为P1,P2,P3...)中选择一些放到背包里,使得在不超过背包体积的情况下,背包内物品的价值总和为最大。

一句话:决定一件物品要不要放进背包的条件是这件物品放进去所带来的总体收益是大于还是小于不放进去的总体收益,也就是对应的动态规划方程为:f(i,v) = max{ f(i-1,v) , f(i-1,v-w[i]) + p[i] },其中f(i,v)表示在体积为V的背包里放i件物品。这个方程的含义就是 在v体积的背包内,放i-1件物品(不放i物品)所带来的收益为f(i-1,v)。 在v体积的背包内,如果要放i物品,那么剩下的体积只有v-w[i],在这么多体积内放i-1件物品所带来的总体收益再加上i物品带来的 收益 就是f(i-1, v-w[i])。那么在v体积内可以放i件物品的时候最大收益就是这以上两种情况的较大者。

二、0/1背包问题的数据结构

w[i] 一维数组: 表示i物品所占体积

p[i] 一维数组: 表示i物品的收益

三、0/1背包问题过程图解

0/1背包问题确实难画图解,网上的现成的也少,我就不好意思省略了。

四、算法源代码

1.0/1背包递归算法

#include<cstdio>
#define MAXN 20

//物品1,2...5的价值
int p[] = {0,6,3,5,4,6};
//物品1,2...5的体积
int w[] = {0,2,2,6,5,4};

//递归算法: 表示当背包总共容量为V的情况下,放i件物品所能获得的最大价值
int f(int i,int V);


//回溯求最优解向量
void traceback(int x[],int n,int ft[][MAXN],int V);

//计算最大值
int max(int a,int b);

//程序执行入口
int main()
{
    printf("Using a recursive algorithm:\n");
    int maxValue = f(5,10);
    printf("when the count of goods is %d and the total volume of the bag is %d,\nthe maxValue is %d\n\n",5,10,maxValue);

     return 0;
}

int max(int a,int b){
    return a>b?a:b;
}

//递归实现 p[] = {0,6,3,5,4,6}; w[] = {0,2,2,6,5,4}; 注意p,w中0只是拿来填充index = 0的时候没什么意义
int f(int i,int V)
{
    //当背包里面物品为0个的时候,价值当然为0
    if(i==0)
        return 0;

    //当所放物品的体积超过背包所提供最大体积
    //当然不能考虑把这个物品放入背包的情况
    if (V < w[i])
        return f(i-1,V);

    //当情况不是上面那样的时候
    //就要考虑把当前 i 物品放入背包
    else
        return max(f(i-1,V),f(i-1,V-w[i])+p[i]);
}



//回溯寻找最优解向量
void traceback(int x[],int n,int ft[][MAXN],int V)
{
    //基本思路就是在最优解成立情况下,如果i物品被放进背包(即x[i] = 1)
    //那么ft[i][V]就是对应的最优子结构,这样给剩下物品提供的总体积减少w[i]
    //如果i物品不放进背包那么x[i] = 0,当然给剩下物品的总体积不变
    for(int i=1;i<=n;i++){
        //这一步比较就是来说明i物品有没有放进去
        //如果放进去f[i][V]和f[i-1][V]肯定是不会相同的
        if(ft[i][V]==ft[i-1][V])
            x[i] = 0;
        else{
            x[i] = 1;
            V-=w[i];
        }
    }
}

2.0/1背包递推算法(加回溯求解向量)

#include<cstdio>
#define MAXN 20

//物品1,2...5的价值
int p[] = {0,6,3,5,4,6};
//物品1,2...5的体积
int w[] = {0,2,2,6,5,4};



//递推算法:
void knapsack(int n,int V,int ft[][MAXN],int p[],int w[]);
//回溯求最优解向量
void traceback(int x[],int n,int ft[][MAXN],int V);
int ft[MAXN][MAXN];
//计算最大值
int max(int a,int b);

//程序执行入口
int main()
{



    printf("Using a recursion algorithm:\n");

    knapsack(5,10,ft,p,w);
    printf("when the count of goods is %d and the total volume of the bag is %d,\nthe maxValue is %d\n",5,10,ft[5][10]);
    int x[MAXN];
    traceback(x,5,ft,10);
    printf("the best answer is (");
    for(int i=1;i<=5;i++)
        printf("%d,",x[i]);
    printf(")\n");

     return 0;
}

int max(int a,int b){
    return a>b?a:b;
}


//递推算法 p[] = {0,6,3,5,4,6}; w[] = {0,2,2,6,5,4}; 注意p,w中0只是拿来填充index = 0的时候没什么意义
void knapsack(int n,int V,int ft[][MAXN],int p[],int w[])
{
    //初始化
    for(int i=0;i<=V;i++){
        ft[0][i] = 0;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=V;j++)
        {
            if(j<w[i])
                ft[i][j] = ft[i-1][j];
            else
                ft[i][j] = max(ft[i-1][j],ft[i-1][j-w[i]]+p[i]);
        }
    }
}

//回溯寻找最优解向量
void traceback(int x[],int n,int ft[][MAXN],int V)
{
    //基本思路就是在最优解成立情况下,如果i物品被放进背包(即x[i] = 1)
    //那么ft[i][V]就是对应的最优子结构,这样给剩下物品提供的总体积减少w[i]
    //如果i物品不放进背包那么x[i] = 0,当然给剩下物品的总体积不变
    for(int i=1;i<=n;i++){
        //这一步比较就是来说明i物品有没有放进去
        //如果放进去f[i][V]和f[i-1][V]肯定是不会相同的
        if(ft[i][V]==ft[i-1][V])
            x[i] = 0;
        else{
            x[i] = 1;
            V-=w[i];
        }
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值