0-1背包问题

发布时间 2023-12-19 22:23:51作者: FBshark

推荐文章:《动态规划之0-1背包问题(详解+分析+原码)

写的很不错。但是动态数组的定义写得不如我下面:

这道题关键在于理解动态规划公式的定义:

可以定义一个二维数组dp[N][C+1],N是物品的种类,C是背包的承重(或者体积)
dp[i][j]是这个数组的一个元素,其值就表示从前i件物品进行选择,在不超过容量j的前提下所满足最大的物品总价值。(注:此处的第i件物品对应与数组下标i)。
 
最核心的代码如下:
    /**
     *
     * @param N 物品数
     * @param C 背包容量
     * @param v 每件的体积
     * @param w 每件物品的价值
     * @return 最大价值
     */
    public int zoKnapsack(int N, int C, int[] v, int[] w) {
        //0-1背包朴素
        int[][] dp = new int[N][C+1];
        //初始化
        for (int j = 0; j <= C; j++) {
            dp[0][j] = j >= v[0] ? w[0] : 0;
        }

        //处理剩余元素
        for (int i = 1; i < N; i++) {
            for (int j = 0; j <= C; j++) {
                //不选
                int x = dp[i-1][j];
                //选
                int y = j >= v[i] ? dp[i-1][j-v[i]] + w[i] : 0;
                //取两者中的最大值
                dp[i][j] = Math.max(x, y);
            }
        }
        return dp[N-1][C];
    }
 
我的完整代码如下(测试可运行):
#include <stdio.h>
#include <stdlib.h>

#define MAX(x, y)    ((x)>(y))?(x):(y)
typedef struct
{
    int weight;
    int value;
}Bagobj;

int SolveBagProb(int N, int M, Bagobj *objlist);
int SolveBagProbPlus(int N, int M, Bagobj *objlist);
int SolveBagProbPlusPlus(int N, int M, Bagobj *objlist);

int main() {
    //输入数据
    int N = 0;
    int M = 0;
    
    //1. 物品的数量
    scanf("%d", &N);
    scanf("%d", &M);

    Bagobj *objlist = (Bagobj *)malloc(sizeof(Bagobj)*N);//使用动态数组
    for(int i=0; i<N; i++)
    {
        scanf("%d", &objlist[i].weight);
    }
    for(int i=0; i<N; i++)
    {
        scanf("%d", &objlist[i].value);
    }
    
    #if 1
    //int res = SolveBagProb(N, M, objlist);
    //int res = SolveBagProbPlus(N, M, objlist);
    int res = SolveBagProbPlusPlus(N, M, objlist);
    printf("%d", res);
    #endif
}

//解决背包问题:
//所需要的数据:物品种类N,背包承重M,每种物品的重量和价值(w,v)
//解法1
int SolveBagProb(int N, int M, Bagobj *objlist)
{
    //初始化一个动态规划数组,dp[N][M+1],初始化其第一行。
    //对于dp[i][j]而言:i是前i个物件,j是背包的承重(变)。
    int dp[N][M+1];
    for(int j=0; j<=M; j++)
    {
        //求价值,错误代码:dp[0][j] = (j>=objlist[0].weight)?(objlist[0].weight):(0);
        dp[0][j] = (j>=(objlist[0].weight))?(objlist[0].value):(0);
        //printf("dp[0][%d] = %d\n",j, dp[0][j]);
    }

    //对下面每一行[1, N-1],求动态规划式子
    int alt_full = 0;
    int alt_notfull = 0;
    for(int i=1; i<N; i++)
    {
        for(int j=0; j<=M; j++)
        {
            alt_full = dp[i-1][j];
            
            int temp_weight = objlist[i].weight;
            if(j >= temp_weight)
            {
                alt_notfull = dp[i-1][j-temp_weight]+objlist[i].value;
            }
            else {
                alt_notfull = 0;
            }
            dp[i][j] = MAX(alt_full, alt_notfull);
            //printf("dp[%d][%d] = %d\n",i,j, dp[i][j]);
        }
    }
    return dp[N-1][M];
}

//解法2
int SolveBagProbPlus(int N, int M, Bagobj *objlist)
{
    //初始化一个动态规划数组,dp[N][M+1],初始化其第一行。
    //对于dp[i][j]而言:i是前i个物件,j是背包的承重(变)。
    int dp[2][M+1];
    for(int j=0; j<=M; j++)
    {
        //求价值,下面这处错误
        //dp[0][j] = (j>=objlist[0].weight)?(objlist[0].weight):(0);
        dp[0][j] = (j>=(objlist[0].weight))?(objlist[0].value):(0);
        //printf("dp[0][%d] = %d\n",j, dp[0][j]);
    }

    //对下面每一行[1, N-1],求动态规划式子
    int alt_full = 0;
    int alt_notfull = 0;
    for(int i=1; i<N; i++)
    {
        for(int j=0; j<=M; j++)
        {
            alt_full = dp[(i-1)&0x01][j];

            int temp_weight = objlist[i].weight;
            if(j >= temp_weight)
            {
                //alt_notfull = dp[i-1][j-temp_weight]+temp_weight;
                alt_notfull = dp[(i-1)&0x01][j-temp_weight]+objlist[i].value;
            }
            else {
                alt_notfull = 0;
            }
            dp[i&0x01][j] = MAX(alt_full, alt_notfull);
            //printf("dp[%d][%d] = %d\n",i,j, dp[i][j]);
        }
    }
    return dp[(N-1)&0x01][M];
}
//解法3
int SolveBagProbPlusPlus(int N, int M, Bagobj *objlist)
{
    //初始化一个动态规划数组,dp[N][M+1],初始化其第一行。
    //对于dp[i][j]而言:i是前i个物件,j是背包的承重(变)。
    int dp[M+1];
    for(int j=0; j<=M; j++)
    {
        //求价值,下面这处错误
        //dp[0][j] = (j>=objlist[0].weight)?(objlist[0].weight):(0);
        dp[j] = (j>=(objlist[0].weight))?(objlist[0].value):(0);
        //printf("dp[0][%d] = %d\n",j, dp[0][j]);
    }

    //对下面每一行[1, N-1],求动态规划式子
    int alt_full = 0;
    int alt_notfull = 0;
    for(int i=1; i<N; i++)
    {
        for(int j=M; j>=0; j--)
        {
            alt_full = dp[j];

            int temp_weight = objlist[i].weight;
            if(j >= temp_weight)
            {
                //alt_notfull = dp[i-1][j-temp_weight]+temp_weight;
                alt_notfull = dp[j-temp_weight]+objlist[i].value;
            }
            else {
                alt_notfull = 0;
            }
            dp[j] = MAX(alt_full, alt_notfull);
            //printf("dp[%d][%d] = %d\n",i,j, dp[i][j]);
        }
    }
    return dp[M];
}