信息学奥赛一本通 1293:买书 | OpenJudge NOI 2.6 6049:买书

【题目链接】

ybt 1293:买书
OpenJudge NOI 2.6 6049:买书

【题目考点】

1. 动态规划:完全背包

完全背包求方案数

【解题思路】

该问题为完全背包求方案数的问题。

1. 状态定义

集合:每种书买多少本构成的方案
限制:在前多少种书中买,买书钱数
属性、条件:书价钱加和等于买书钱数
统计量:方案数
状态定义dp[i][j]:在前i种书中选书购买,总价钱为j元的方案数
初始状态:在前i种书中选书购买,总价格为0元的方案,就是不选书,有一种方案。即dp[i][0]=1

2. 状态转移方程

a[i]为第i种书的价钱
集合:在前i种书中选择书价钱加和为j的方案
分割集合:是否选择第i种书

  • 如果选择一本第i种书,接下来要在前i种书中选择书,价钱加和为j-a[i],方案数为:dp[i][j-a[i]]
  • 如果不选择第i种书,接下来要在前i-1种书中选择书,价钱加和为j,方案数为dp[i-1][j]
  • 两种情况的方案数加和,为在前i种书中选择书价钱加和为j的方案数,即dp[i][j] = dp[i][j-a[i]] + dp[i-1][j]

可以进行滚动数组优化。

【题解代码】

解法1:基本解法
#include<bits/stdc++.h>
using namespace std;
#define N 15
#define M 1005
int n, m, a[N] = {0, 10, 20, 50, 100};//a[i]:第i本书的钱数 
int dp[N][M];//dp[i][j]:在前i种书中选书购买,总价钱为j元的方案数
int main()
{
    m = 4;//书的种类 
    cin >> n;
    for(int i = 0; i <= m; ++i)
        dp[i][0] = 1;
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= n; ++j)
        {
            if(j >= a[i])
                dp[i][j] = dp[i][j-a[i]] + dp[i-1][j];
            else
                dp[i][j] = dp[i-1][j];
        }
    cout << dp[m][n];
    return 0;
}
解法2:滚动数组优化
#include<bits/stdc++.h>
using namespace std;
#define N 15
#define M 1005
int n, m, a[N] = {0, 10, 20, 50, 100};//a[i]:第i本书的钱数 
int dp[M];//dp[i][j]:在前i种书中选书购买,总价钱为j元的方案数
int main()
{
    m = 4;//书的种类 
    cin >> n;
    dp[0] = 1;
    for(int i = 1; i <= m; ++i)
        for(int j = a[i]; j <= n; ++j)
            dp[j] = dp[j-a[i]] + dp[j];
    cout << dp[n];
    return 0;
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值