Coins

题目

给出硬币面额及每种硬币的个数,求从1到m能凑出面额的个数。

思路

1.朴素的多重背包

题面给出的很明显的多重背包,定义dp为考虑前i种硬币,能凑出j元的方案可行性,可以得到第一版代码

O(nm^2) 代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<fstream>
#define inf 0x3f3f3f3f
#define ll long long
#define ull unsigned long long
#define endl '\n'
#define debug(x) printf("x--->%lld\n",x)
//#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N =10 + 1e5, mod = 1e9 + 7;
int n,m;
bool dp[110][N];
int a[110],b[1000];// amax = 1e5 bmax = 1000
void solve()
{    for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++)cin>>b[i];memset(dp,0,sizeof dp);dp[0][0] = 1;for(int i=1;i<=n;i++)for(int j=0; j<=m;j++){int v=a[i];dp[i][j] = dp[i-1][j];//已经在之前凑出if(dp[i][j])continue;for(int k=0;k<=b[i] && j-v*k>=0;k++)// 查找要几枚才可能凑出jif(dp[i-1][j-v*k]){dp[i][j]=1;break;} }// for(int i=1;i<=m;i++)cout<<dp[n][i]<<' ';cout<<endl;ll ans = 0 ;for(int j=1;j<=m;j++)ans+= (dp[n][j]!=0);cout << ans << endl;
}
signed main()
{ios::sync_with_stdio();cin.tie();cout.tie();while(cin>>n>>m,(n||m))solve();return 0;
}

显然上面的代码时间复杂度是无法接受的,考虑到dp是bool型,事实上丢掉了

很多信息,所以考虑修改dp定义,增加dp记录的信息,优化时间。

2.时间优化

我们定义 dp 为考虑前i种硬币凑出j元的所有方案的集合,而其中储存第i种硬币的凑出j后的剩余数量,并规定,dp[i][j[] = -1 ,代表无法凑出 j。
通过上述定义,如果 dp[i][j] = -1 表示无法凑出j ,其余表示方案可行,一样可以得到本题答案。
同时,对于dp[i][j] 可以确定是从 dp[i-1][j](考虑i-1种,凑出j元) 和 dp[i][j-v](考虑i种,还差一个第i种硬币就凑出 j ,这两个状态转移过来,这样就不用再暴力查找j 的前状态来确定 dp[i][j] 了

状态转移:

  • dp[i][j] <== dp[i-1][j] or dp[i-1][k]
  • dp[i][j] <== dp[i-1][j] or dp[i][j-vi]

成功把下面的循环优化掉

 for(int k=0;k<=b[i] && j-v*k>=0;k++)// 查找要几枚才可能凑出jif(dp[i-1][j-v*k]){dp[i][j]=1;break;}

3.空间优化

本题卡空间,所以还要把二维dp优化为一维,较容易解决

  • 对于 dp[i-1][j] => dp[i][j] <==> dp[j] (old) ⇒ dp[j] (new)
  • 对于 dp[i][j-vi] => dp[i][j] <==> dp[j-vi] (new) ⇒ dp[j] (new)

最终代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<fstream>
#define inf 0x3f3f3f3f
#define ll long long
#define ull unsigned long long
#define endl '\n'
#define debug(x) printf("x--->%lld\n",x)
//#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N =10 + 1e5, mod = 1e9 + 7;
int n,m;
int dp[N];// dp[110][N];
int a[110],b[1000];// amax = 1e5 bmax = 1000
void solve()
{    for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++)cin>>b[i];memset(dp,-1,sizeof dp);dp[0] = 0;// 规定 dp[0] 合法for(int i=1;i<=n;i++)for(int j=0;j<=m;j++){// 朴素空间做法 与下面相等价/* if(dp[i-1][j]>=0)dp[i][j] = b[i];else{if(j-a[i]>=0 && dp[i][j-a[i]]>0)dp[i][j] = dp[i][j-a[i]] - 1;else dp[i][j] = -1;} */if(dp[j]>=0)// 已经凑齐j 第i种硬币全部剩下dp[j] = b[i];else{  // 未凑齐if(j-a[i] >=0 && dp[j-a[i]] > 0) // 合法 且 仍有硬币剩余dp[j]  = dp[j-a[i]] -1;}// 剩下未更新的即无法凑出 不合法}ll ans = 0;for(int i=1;i<=m;i++) ans += dp[i]>=0;cout << ans <<endl;
}
signed main()
{ios::sync_with_stdio();cin.tie();cout.tie();while(cin>>n>>m,n||m)solve();return 0;
}

Coins(多重背包方案可行性dp + 优化)相关推荐

  1. 多重背包单调队列优化思路_多重背包之单调队列优化理论性总结

    多重背包之单调队列优化: 若用F[j]表示对容量为j的背包,处理完前i种物品后,背包内物品可达到的最大总价值,并记m = min(n, j / v).放入背包的第i种物品的数目可以是:0.1.2--, ...

  2. 多重背包:经典DP问题( 基本/二进制优化/单调队列优化 )

    目录 基本方法 **二进制优化 *****单调队列优化 多重背包问题描述:介于01背包和完全背包问题之间,每种物品的最大选取数目都是已知的. 对于一定数量( i )的物品有一个容量为( j )的背包, ...

  3. Coins (多重背包)模板题

    模板请看上一篇博客 Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. One day Hibi ...

  4. 背包模型dp1:01背包,完全背包,多重背包的两大优化的详解

    01背包问题: 状态表示:f[i][j]表示从只从前i个物体里面选,切总体积不超过j的选法的集合状态表示:f[i][j]表示从只从前i个物体里面选,切总体积不超过j的选法的集合状态表示:f[i][j] ...

  5. HDU - 2844 Coins(多重背包+完全背包)

    题意 给n个币的价值和其数量,问能组合成\(1-m\)中多少个不同的值. 分析 对\(c[i]*a[i]>=m\)的币,相当于完全背包:\(c[i]*a[i]<m\)的币则是多重背包,考虑 ...

  6. HDU 2844 Coins 多重背包

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2844 Coins Time Limit: 2000/1000 MS (Java/Others)Mem ...

  7. 【POJ3260】The Fewest Coins 多重背包+完全背包

    A来B处买东西,价值M元,有N种钱,每种钱A有一定数量,而B有无限数量. 求最少用多少张钞票可以满足交易,比如样例,A出50+25,B找5,即可满足,需要3张. A用多重背包转移状态,B用完全背包. ...

  8. jzoj100044-abcd【多重背包,二进制压缩,dp】

    正题 题目大意 给出长度为nnn的序列a,b,c,da,b,c,da,b,c,d 求一个序列eee满足 (∑i=1nei∗ci)=0(e∈[ai..bi])(\sum _{i=1}^ne_i*c_i) ...

  9. HDU 2844 Coins (多重背包)

    题目链接 题意:Tony想要买一个东西,他只有n种硬币,每种硬币的面值为a[i],每种硬币的数量为c[i],要买的物品价值不超过m,输出1-m中有多少种价格Tony可以用硬币组合出来. 题解:多重背包 ...

最新文章

  1. oracle增量备份如何恢复,【Oracle】增量备份和全库备份怎么恢复数据库
  2. 滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(4月7日)...
  3. ip地址详解,ip地址各种写法的意义,私有局域网搭建(IPv4)
  4. C++ 数值的整数次方 (最小int取反,递归实现乘方)
  5. 检测和语义分割_分割和对象检测-第1部分
  6. Xdebug 使用说明
  7. sql语句中查询出的数据添加一列,并且添加默认值
  8. 关于JVM的几个问题
  9. 怎么下载英文文献呢?
  10. 电工培训维修电工基础知识实训教学
  11. 用于遥感图像语义分割和单视图高度估计的编码器-双解码器IGARSS2019
  12. 中国石油大学《工程概预算与招投标》第三阶段在线作业
  13. php对接腾讯云直播
  14. Mockplus原型设计工具介绍
  15. java/php/net/python志愿者管理系统程序设计
  16. Python图形界面实现咖啡店点单系统
  17. GitLab 如何删除 Forked from
  18. 剑指Offe 50:数组中重复的数字
  19. 云直播SDK核心功能对比|腾讯云、阿里云、声网、即构等SDK厂商对比
  20. 下载网站特有字体图标方法

热门文章

  1. 电力电子技术:电力电子器件
  2. Spring中IoC和DI的理解
  3. 敏捷日记(2012年3月到2012年5月)
  4. signature=a6cb6ce8d8e12b283f4fc618f250a727,MS12-041:Windows 内核模式驱动程序中的漏洞可能会允许特权提升:2012 年 6 月 12 日...
  5. 有限元三角形单元的等效节点力
  6. 一个和CSDN类似的博客网站
  7. 36氪首发|「优仕美地医疗」获亿元级B轮融资,要打造日间手术机构的连锁服务网络...
  8. 行业前沿研究 - 优士网
  9. 2015年三分之一程总结1——工作生活总结(多图慎入)
  10. 抽象类、接口、Objext 详解