js 背包问题之01背包(附C++代码)

4 篇文章 0 订阅

题目描述

 /*  01背包问题
            题目描述
                一个旅行者有一个最大能装M公斤的背包,现在有N件物品,他们的重量分别是Wi,
                价值分别是Vi,求旅行者能获得的最大总价值
            输入
                第一行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30);
                第2到 N+1 行: 每行两个整数W[i],V[i],表示每个物品的重量和价值
            输出
                仅一行,一个数,表示最大的总价值

            测试样例
                10  4
                2   1
                3   3
                4   5
                7   9
                输出 -> 12
        */

分析

动态规划实现,详细分析教程移步下方传送门,讲得非常详细(就是时间有点儿长,55分钟)。

https://www.bilibili.com/video/BV1C7411K79w?from=search&seid=554744848366710695

核心在于,状态转移方程式的推算,01背包的状态转移方程式为:

dp[i][j] = max {dp[i-1][j],dp[i-1][j-W[i]] + V[i]}

其中,dp代表动态规划的二维表,i表示第几件物品,j表示当前背包总容量。

js代码

// 创建完全二维数组函数
 const createFullTwoDimenArray = (len, width, num = '') => new Array(len).fill(num).map(item => new Array(width).fill(num))

 // 基础解题,二维数组动态规划
 const package_01 = (M, N, W, V) => {
     // dp 数组 dp[i][0] = 0 dp[0][j] = 0 防止下标运算越界
     const dp = createFullTwoDimenArray(N + 1, M + 1, 0)

     for (let i = 1; i <= N; i++) {
         for (let j = 1; j <= M; j++) {
             if (j < W[i])
                 dp[i][j] = dp[i - 1][j]
             else
                 dp[i][j] = dp[i - 1][j] >= dp[i - 1][j - W[i]] + V[i] ? dp[i - 1][j] : dp[i - 1][j - W[i]] + V[i]
         }
     }

     return dp[N][M]
 }
 // 优化版本,一维滚动数组
 // 因为后无效性原则:当前状态只与上一次的状态有关
 // 其实每次只用到了上一次统计过的数据,所有可以讲二维表优化成为一维的数组不停的覆盖运算即可
 const package_01_ScrollingArray = (M, N, W, V) => {
     const dp = new Array(M + 1).fill(0)

     for (let i = 1; i <= N; i++) {
         for (let j = M; j >= 1; j--) {
             if (j >= W[i])
                 dp[j] = dp[j] >= dp[j - W[i]] + V[i] ? dp[j] : dp[j - W[i]] + V[i]
         }
     }

     return dp[M]
 }

 // 测试数据
 // <详细输入太麻烦了,直接把测试数据写死了>
 const W = [0, 2, 3, 4, 7] // 每个物品的重量,0位 置0
 const V = [0, 1, 3, 5, 9] // 每个物品的价值,0位 置0
 const M = 10 // 背包容量
 const N = 4 // 物品数量
 
 console.log('最大的总价值:', package_01(M, N, W, V))
 console.log('最大的总价值:', package_01_ScrollingArray(M, N, W, V))

C++代码

     #include <iostream>
     using namespace std;

     int dp[32][202]
     int W[32],V[32]

     int main(){
         int m,n;
         cin>>m>>n;
         for(int i=1;i<=n;i++){
             cin>>W[i]>>V[i];
         }
         for(int i=1;i<=n;i++){
             for(int j=1;j<=m;j++){
                 if (j<W[i])
                     dp[i][j] = dp[i-1][j];
                 else 
                     dp[i][j] = max(dp[i-1][j],dp[i-1][j-W[i]] + V[i]);
             }
         }

         cout<<dp[n][m];
         return 0;
     }
 // 滚动数组
     #include <iostream>
     using namespace std;

     int W[32],V[32],dp[202]

     int main(){
         int m,n;
         cin>>m>>n;
         for(int i=1;i<=n;i++){
             cin>>W[i]>>V[i];
         }
         for(int i=1;i<=n;i++){
             for(int j=w;j>=1;j--){
                 if (j>=W[i])
                     dp[j] = max(dp[j],dp[j-W[i]] + V[i]);
             }
         }

         cout<<dp[m];
         return 0;
     }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值