[ABC286D] Money in Hand 记忆化搜索实现多重背包

萌新第一次在csdn写题解,同时算的上是个人笔记,有错误请大佬多多指教。

该题链接:[ABC286D] Money in Hand - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题目大意(摘自洛谷):

有 n 种纸币,其中对于第 i(1≤i≤n) 种纸币,它的面值是 ai​ 元,我们有 bi​ 张这种纸币。

请求出在不找零的情况下,用这些纸币能否正好付 x 元,如果能则输出 Yes,不能则输出 No

答案很显然,是多重背包的模板题,因为数据范围很小,我们可以不采用二进制优化版的算法,直接枚举每个物品的数量,即:

                 ​​​​​​​        ​​​​​​​        ​​​​​​​        dp_{i,j}|=dp_{i-1,j-k*a[i]}

这里dp_{i,j}表示选择k张面值为a[i]的纸币的方案,当dp_{n,m}不为0时存在方案,这是常规作法,而我这里采用记忆化搜索的方式实现多重背包,记忆化搜索就是对搜的每一个状态做一个记录防止重复搜索降低时间复杂度,这里我采用从后往前的方式,所以是dp_{i-1,j+k*a[i]},当i搜完了以后j刚好为m的时候输出yes,反之输出no.

#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
using ll=long long ;
using pii=pair<int,int> ;
#define endl "\n"

constexpr int N=55;
constexpr int M=10010;

int n,m;
int dp[N][M];
int a[N],b[N];

int dfs(int i,int j)
{
    if(i<=0)
    {
        if(j==m)return 1;
        return 0;
    }
    
    if(j>m||dp[i][j])return 0;
    
    dp[i][j]=1;
    
    for(int k=0;k<=b[i];k++)
    if(dfs(i-1,j+a[i]*k))
    {
        return 1;
    }
    
    return 0;
}

void solve()
{
    
    cin>>n>>m;
   
    for(int i=1;i<=n;i++)
    cin>>a[i]>>b[i];
    
    if(!dfs(n,0))cout<<"No"<<endl;
    else cout<<"Yes"<<endl;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    
    int t;
    t=1;
    
    while(t--)
    solve();
    return 0;
}

  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值