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

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

5个月前 (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;
}





原创内容 转载请注明出处

分享给朋友:

相关文章

70.爬楼梯|三步破解动态规划核心奥秘

70.爬楼梯|三步破解动态规划核心奥秘

题意新解:站在楼梯底仰望n级台阶,每步可选1或2阶,最终的路径组合犹如斐波那契数列般展开。比如到达第3阶的路径可由第1阶跨两步,或第2阶跨一步构成,这种递推规律揭示了两两相邻状态间的紧密关联。思路解析...

NOIP2005 普及组 洛谷P1408 背包问题的空间优化技巧与实战应用

NOIP2005 普及组 洛谷P1408 背包问题的空间优化技巧与实战应用

题目重解想象你是一名药师,有t分钟在山上采集m种草药。每种草药需要time分钟采集,价值为num。这就像考试时分配时间做题,要选择收益最大的题目组合。题目要求计算在规定时间内能获得的最大草药价值。解题...

2024年GESP五级武器强化(洛谷B4071)解题代码C++版

2024年GESP五级武器强化(洛谷B4071)解题代码C++版

一、题目解读    2024年GESP(青少年软件编程能力等级考试)五级中的“武器强化”(洛谷平台题目编号B4071)是一道典型的算法优化问题。题目要求通过合理...

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

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

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

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

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

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

洛谷P4551题解题报告:图论与Trie树优化异或路径问题的实战解析

洛谷P4551题解题报告:图论与Trie树优化异或路径问题的实战解析

一、题目解读洛谷P4551题要求在一个无向图中,寻找任意两点路径权值异或后的最大值。题目输入为图的边信息(点数n和n-1条边),每条边包含起点、终点及权值。需输出所有路径中权值异或的最大值。问题核心在...

发表评论

访客

看不清,换一张

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