ad1 广告
 
收藏文章 楼主

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

版块:文章资讯   类型:普通   作者:某个人   查看:28   回复:0   获赞:0   时间:2025-05-27 13:13:03

从零到一掌握背包问题:洛谷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元的方案总数。

代码+注释:

C++

#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)。核心思想是发现每次状态转移只依赖于前一轮的状态,因此只需要维护两行数组即可。

C++

#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;
}

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


 
ad1 广告位8,870 x auto
回复列表
默认   热门   正序   倒序

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

Powered by 免费外链论坛

©2015 - 2025 免费外链论坛

免费外链论坛 免费发布外链 发外链平台Sitemap

您的IP:216.73.216.80,2025-06-17 05:52:18,Processed in 0.02636 second(s).

备案信息:浙ICP备2024090696号

声明:本站内容为用户自主发布,不对其内容真实性负责,虽然本站会一一审核,但能力有限,如您发现违规内容,请及时联系管理员。

主页

欢迎您的浏览

QQ联系图标

自助查询

99%的问题都能找到答案

联系站长

工作时间:9:00~17:30

微信二维码

回到顶部

向上滚动到顶部

个人中心

去个人首页看看吧

转到底部

向下滚动到底部

头像

用户名:

粉丝数:

签名:

资料 关注 好友 消息