当前位置:首页 > 洛谷 > 从零到一掌握背包问题:洛谷P1164题解精讲,附带优化

从零到一掌握背包问题:洛谷P1164题解精讲,附带优化

7个月前 (05-24)

从零到一掌握背包问题:洛谷P1164题解精讲,附带优化 洛谷 动态规划 滚动数组  01背包 状态转移方程 第1张

题目重解:

小A带着m元钱来到餐馆,菜单上有n道菜,每道菜都有确定的价格。现在需要计算出刚好花完m元的点菜方案总数。这个问题看似简单,但当菜品数量增多时,暴力枚举就会变得不可行,需要更高效的算法来解决。

解题思路:

动态规划方法解决这个问题。首先定义一个二维数组dp,其中dp[i][j]表示前i道菜花费j元的方案数。初始化时,dp[0][0]为1(0道菜花0元有1种方案)。然后通过双重循环遍历每道菜和每个可能的金额:

1.当当前菜品价格大于当前金额时,直接继承前i-1道菜的结果

2.当金额正好等于菜品价格时,方案数增加1(单独点这道菜)

3.当金额大于菜品价格时,方案数为不选这道菜的方案数加上选了这道菜后剩余金额的方案数之和 最终dp[n][m]就存储了恰好花完m元的方案总数。

代码+注释:

#include<iostream>
using namespace std;

int main()
{
    int n,m;  // n是菜品数量,m是总金额
    cin>>n>>m;
    int* a=new int[n];  // 存储每道菜的价格
    for(int i=0;i<n;i++)
        cin>>a[i];
    
    // 初始化动态规划数组
    int** dp=new int*[n+1];
    for(int i=0;i<=n;i++){
        dp[i]=new int[m+1];
        for(int j=0;j<=m;j++) dp[i][j]=0; // 初始化为0
    }
    dp[0][0]=1;  // 基础情况:0道菜花0元有1种方案

    // 动态规划过程
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(j<a[i-1]) dp[i][j]=dp[i-1][j];  // 当前菜太贵,无法选择
            else if(j==a[i-1]) dp[i][j]=dp[i-1][j]+1;  // 刚好可以单独点这道菜
            else dp[i][j]=dp[i-1][j]+dp[i-1][j-a[i-1]];  // 不选或选这道菜两种情况之和
        }
    }
    cout<<dp[n][m];  // 输出最终结果

    // 释放内存
    for(int i=0;i<=n;i++) delete[] dp[i];
    delete[] dp;
    delete[] a;
    return 0;
}

 空间优化:

通过滚动数组技术将空间复杂度从O(nm)降低到O(m)。核心思想是发现每次状态转移只依赖于前一轮的状态,因此只需要维护两行数组即可。

#include<iostream>
using namespace std;

int main()
{
    int n,m;  // n菜品数,m总金额
    cin>>n>>m;
    int a;  // 当前菜品价格
    
    // 只申请两行的滚动数组
    int** dp=new int*[2];
    for(int i=0;i<2;i++){
        dp[i]=new int[m+1]{0};  // 初始化为0
    }
    dp[0][0] = 1;  // 基础状态
    
    bool now=0;  // 当前行标识(0/1)
    for(int i=1;i<=n;i++){
        cin>>a;
        for(int j=1;j<=m;j++){
            if(j<a) dp[now][j]=dp[now^1][j];
            else if(j==a) dp[now][j]=dp[now^1][j]+1;
            else dp[now][j]=dp[now^1][j]+dp[now^1][j-a];
        }
        now^=1;  // 切换当前行
    }
    cout<<dp[now^1][m];  // 输出最终结果
    
    // 释放内存
    for(int i=0;i<2;i++) delete[] dp[i];
    delete[] dp;
    return 0;
}





原创内容 转载请注明出处

分享给朋友:

相关文章

【动态规划入门】力扣509题:斐波那契数列的经典解法与优化思路

【动态规划入门】力扣509题:斐波那契数列的经典解法与优化思路

题目解读‌斐波那契数列是一个经典的数学问题,在计算机科学中常被用作算法教学的入门案例。这个神奇的数列从0和1开始,后续每个数字都是前两个数字之和。题目要求我们计算第n个斐波那契数,看似简单的问题背后却...

CSP-J 2019纪念品题解(洛谷P5662):动态规划+完全背包问题的实战应用

CSP-J 2019纪念品题解(洛谷P5662):动态规划+完全背包问题的实战应用

一、题目解读2019年CSP-J的“纪念品”问题(对应洛谷P5662)要求玩家在T天内通过买卖纪念品最大化金币收益。每天可交易N种商品,需计算最优策略下的最终金币数。题目强调动态规划思维与资源分配优化...

CSP-J方格取数题解|动态规划解法|洛谷P7074代码解析

CSP-J方格取数题解|动态规划解法|洛谷P7074代码解析

一、题目解读题目要求在一个n×m的网格中,从左上角到右下角选择一条路径,路径上的数字可重复取用,求取数之和的最大值。路径限制为仅能向右或向下移动。需注意路径的灵活性与重复取数的可能性,传统单向动态规划...

NOIP 2008火柴棒等式题解(C++代码实现)  动态规划与枚举算法详解

NOIP 2008火柴棒等式题解(C++代码实现) 动态规划与枚举算法详解

一、题目解读火柴棒等式问题(NOIP 2008,洛谷P1149)要求使用给定数量的火柴棒,构造形如 A + B = C 的等式,其中A、B、C均为整数,且火柴棒总数恰好等于输入值。需统计符合条件的等式...

2024蓝桥杯省赛B组“传送阵”题解(C++代码+图论算法优化)

2024蓝桥杯省赛B组“传送阵”题解(C++代码+图论算法优化)

一、题目解读2024年蓝桥杯省B组“传送阵”题目要求处理一个包含n个节点的图,节点间存在单向传输关系。每个节点i可传送至a[i]指定的节点,形成可能存在的环结构。题目需求解从任意节点出发能到达的最长路...

CSP-J 2019公交换乘题解析:基于队列优化的动态规划代码详解

CSP-J 2019公交换乘题解析:基于队列优化的动态规划代码详解

一、题目解读CSP-J 2019年的“公交换乘”题目(洛谷P5661)要求模拟地铁与公交交替出行的费用计算。题目核心在于地铁消费会产生优惠券,而公交可在45分钟内使用优惠券抵扣车费。需要处理n条出行记...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。