萌新第一次在csdn写题解,同时算的上是个人笔记,有错误请大佬多多指教。
该题链接:[ABC286D] Money in Hand - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目大意(摘自洛谷):
有 n 种纸币,其中对于第 i(1≤i≤n) 种纸币,它的面值是 ai 元,我们有 bi 张这种纸币。
请求出在不找零的情况下,用这些纸币能否正好付 x 元,如果能则输出 Yes
,不能则输出 No
。
答案很显然,是多重背包的模板题,因为数据范围很小,我们可以不采用二进制优化版的算法,直接枚举每个物品的数量,即:
这里表示选择k张面值为a[i]的纸币的方案,当不为0时存在方案,这是常规作法,而我这里采用记忆化搜索的方式实现多重背包,记忆化搜索就是对搜的每一个状态做一个记录防止重复搜索降低时间复杂度,这里我采用从后往前的方式,所以是,当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;
}