动态规划——01背包问题

本文围绕动态规划解决01背包问题展开。先介绍问题内容,即给定物品重量、价值和背包容量,求装入物品的最大总价值。接着进行问题分析,通过维护二维数组求物品总价值,给出算法步骤,还介绍用回溯法求选择的物品,最后提及源代码和运行结果。

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

动态规划——01背包问题

问题内容

给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?

0-1背包问题是一个特殊的整数规划问题。
在这里插入图片描述

问题分析

求物品的总价值

  • 采用动态规划的思想,维护一个二维数组dp[i][j]

  • 该数组表示为当有前i个物品选择且背包容量为j时最优价值

    例如,

    物品的价值:8,50,12,20,10

    物品的重量:3,20,5,10,5

    dp[1][1]表示物品的选择范围只有第一个,且背包现在的容量为1,那么最大价值为0

    dp[1][3] 表示物品的选择范围只有第一个,且背包现在的容量为3,那么最大价值为8

    dp[2][20] 表示物品的选择范围有第一和第二个,且背包现在的容量为20,那么最大价值为50

  • 原问题的解即为dp[i][j]数组中的最大值即为dp[n][c](n为物品的数量,c为背包的重量)

  • 最长连续上升子序列可以通过s[i]中的下标以及该元素中的值决定

算法步骤

  • 输入原始数组w[n],v[n]分别表示物品的重量和价值,以及需要维护的数组dp[n][c](初始值为零)

  • 两重循环,分别遍历物品i,和背包的重量j(目的是得到每种重量之下的最优值,并可以为后面的所需进行数值递推)

  • 遍历的过程中:

    如果当前所选物品的重量大于背包的中量便采取不放入背包,即当前的dp[i][j]=dp[i-1][j]

    如果当前所选物品的重量小于背包的重量便有两种情况

    (1) 放入的该物品还没有不放入该物品产生的价值大,那么当前的背包的价值依然为不放入该物品的价值,即dp[i][j]=dp[i-1][j]

    (2) 放入的该物品比放入该物品产生的价值大,那么当前的背包的价值为放入该物品的价值,即dp[i][j]=dp[i-1][j-w[i]]+v[i]

  • 循环结束即可得到一张二维表,dp[n][c]便是n中物品选择下,背包重量为c的最优价值

求选择的物品

采用回溯法,在已有的dp表中回溯源,因为dp[i][j]无非是通过dp[i-1][j]或者dp[i-1][j-w[j]]求得

  • 如果当前的dp[i][j]是通过dp[i-1][j]求得,意味着并没有选择该物品,便回溯到dp[i-1][j]的位置

  • 如果当前的dp[i][j]是通过dp[i-1][j-w[i]],意味着选择该物品,便回溯到dp[i-1][j-w[i]]

源代码

#include <bits/stdc++.h>
using namespace std;
const int N=6;
int v[N]={0,8,50,12,20,10};
int w[N]={0,3,20,5,10,5};
int c=30;
int dp[6][31];//当有前i个物品选择背包容量为j时最优价值
int vis[6];
void findwhere(int i,int j){
    if(i>0) {
        if(dp[i][j]==dp[i-1][j]){vis[i]=0;findwhere(i-1,j);}
        else{
            if(dp[i][j]=dp[i-1][j-w[i]]+v[i]){
                vis[i]=1;
                findwhere(i-1,j-w[i]);
            }
        }
    }
}
void print_vis(){
    for(int i=1;i<N;i++){
        cout<<vis[i]<<" ";
    }
    cout<<endl;
}
int main() {
    for(int i=1;i<=N;i++){
        for (int j = 1; j <=c; ++j) {
            if(j<w[i]){dp[i][j]=dp[i-1][j];}
            else{
                if(dp[i-1][j]>dp[i-1][j-w[i]]+v[i]){dp[i][j]=dp[i-1][j];}
                else{dp[i][j]=dp[i-1][j-w[i]]+v[i];}
            }
        }
    }
    cout<<"max="<<dp[N][c]<<endl;
    findwhere(N,c);
    print_vis();
    return 0;
}

运行结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值