Coins(多重背包方案可行性dp + 优化)
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 + 优化)相关推荐
- 多重背包单调队列优化思路_多重背包之单调队列优化理论性总结
多重背包之单调队列优化: 若用F[j]表示对容量为j的背包,处理完前i种物品后,背包内物品可达到的最大总价值,并记m = min(n, j / v).放入背包的第i种物品的数目可以是:0.1.2--, ...
- 多重背包:经典DP问题( 基本/二进制优化/单调队列优化 )
目录 基本方法 **二进制优化 *****单调队列优化 多重背包问题描述:介于01背包和完全背包问题之间,每种物品的最大选取数目都是已知的. 对于一定数量( i )的物品有一个容量为( j )的背包, ...
- Coins (多重背包)模板题
模板请看上一篇博客 Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. One day Hibi ...
- 背包模型dp1:01背包,完全背包,多重背包的两大优化的详解
01背包问题: 状态表示:f[i][j]表示从只从前i个物体里面选,切总体积不超过j的选法的集合状态表示:f[i][j]表示从只从前i个物体里面选,切总体积不超过j的选法的集合状态表示:f[i][j] ...
- HDU - 2844 Coins(多重背包+完全背包)
题意 给n个币的价值和其数量,问能组合成\(1-m\)中多少个不同的值. 分析 对\(c[i]*a[i]>=m\)的币,相当于完全背包:\(c[i]*a[i]<m\)的币则是多重背包,考虑 ...
- HDU 2844 Coins 多重背包
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2844 Coins Time Limit: 2000/1000 MS (Java/Others)Mem ...
- 【POJ3260】The Fewest Coins 多重背包+完全背包
A来B处买东西,价值M元,有N种钱,每种钱A有一定数量,而B有无限数量. 求最少用多少张钞票可以满足交易,比如样例,A出50+25,B找5,即可满足,需要3张. A用多重背包转移状态,B用完全背包. ...
- 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) ...
- HDU 2844 Coins (多重背包)
题目链接 题意:Tony想要买一个东西,他只有n种硬币,每种硬币的面值为a[i],每种硬币的数量为c[i],要买的物品价值不超过m,输出1-m中有多少种价格Tony可以用硬币组合出来. 题解:多重背包 ...
最新文章
- oracle增量备份如何恢复,【Oracle】增量备份和全库备份怎么恢复数据库
- 滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(4月7日)...
- ip地址详解,ip地址各种写法的意义,私有局域网搭建(IPv4)
- C++ 数值的整数次方 (最小int取反,递归实现乘方)
- 检测和语义分割_分割和对象检测-第1部分
- Xdebug 使用说明
- sql语句中查询出的数据添加一列,并且添加默认值
- 关于JVM的几个问题
- 怎么下载英文文献呢?
- 电工培训维修电工基础知识实训教学
- 用于遥感图像语义分割和单视图高度估计的编码器-双解码器IGARSS2019
- 中国石油大学《工程概预算与招投标》第三阶段在线作业
- php对接腾讯云直播
- Mockplus原型设计工具介绍
- java/php/net/python志愿者管理系统程序设计
- Python图形界面实现咖啡店点单系统
- GitLab 如何删除 Forked from
- 剑指Offe 50:数组中重复的数字
- 云直播SDK核心功能对比|腾讯云、阿里云、声网、即构等SDK厂商对比
- 下载网站特有字体图标方法
热门文章
- 电力电子技术:电力电子器件
- Spring中IoC和DI的理解
- 敏捷日记(2012年3月到2012年5月)
- signature=a6cb6ce8d8e12b283f4fc618f250a727,MS12-041:Windows 内核模式驱动程序中的漏洞可能会允许特权提升:2012 年 6 月 12 日...
- 有限元三角形单元的等效节点力
- 一个和CSDN类似的博客网站
- 36氪首发|「优仕美地医疗」获亿元级B轮融资,要打造日间手术机构的连锁服务网络...
- 行业前沿研究 - 优士网
- 2015年三分之一程总结1——工作生活总结(多图慎入)
- 抽象类、接口、Objext 详解