<---- 麻烦点一下旁边那个向上的三角
推销一下:
$\color{#00FF7F}{算法提高课 第一章 动态规划 全题解(正在完善)}$
题目描述
给你一个$n$种面值的货币系统,求组成面值为$m$的货币有多少种方案。
输入格式
第一行,包含两个整数$n$和$m$。
接下来$n$行,每行包含一个整数,表示一种货币的面值。
输出格式
共一行,包含一个整数,表示方案数。
数据范围
$n≤15,m≤3000$
输入样例:
3 10
1
2
5
输出样例:
10
题意简述
给定 $n$ 种面值的货币,求组成面值为 $m$ 的货币有多少种方案。
注意:
每种面值的货币可以重复使用
每种方案必须是组成的面值恰好等于$m$
求的是方案数量,不是最大价值
算法1
(二维动态规划) $O(n^3)$
这道题只要抽象好表述,就能很快与 AcWing 1023. 买书 一题对应,从而快速解决问题。
根据
组成面值为 $m$ 的货币
可以感受到,可以将 $m$ 抽象为背包容量。
那物品是什么呢,除了 $m$ 只剩下 $n$ 种面值的货币。
那我们将其抽象为物品体积,并将物品放入背包,求方案数。
整理:
- 组成面值为 $m$ 的货币 $\to$ 背包容量
- $n$ 种面值的货币 $\to$ 物品体积
求方案数量我们可以参考最初的 AcWing 278. 数字组合 01背包求方案数量问题。
注意到隐藏条件:货币有无数张。可以判断为完全背包求方案数量问题。
时间复杂度
参考文献
C++ 代码
#include <iostream>
using namespace std;
const int N = 3010;
int v[N];
long long f[N][N];
int main(){
int n,m;
scanf("%d%d",&n,&m);
f[0][0] = 1;
for(int i = 1;i <= n;i ++) scanf("%d",&v[i]);
for(int i = 1;i <= n;i ++){
for(int j = 0;j <= m;j ++){
for(int k = 0;v[i] * k <= j;k ++){
f[i][j] += f[i - 1][j - v[i] * k];
}
}
}
printf("%lld",f[n][m]);
return 0;
}
注意:
这里的 $f$ 数组会爆 $int$,所以要用$long \ long$
如果你是用 $printf$ 输出,记得是printf("%lld",f[n][m])
算法2
(一维数组DP) $O(n^2)$
这里我就只把最初和最后的代码放出来啦,其他方法可以看一下我买书那题的题解
时间复杂度
参考文献
C++ 代码
#include <iostream>
using namespace std;
const int N = 3010;
int v[N];
long long f[N];
int main(){
int n,m;
scanf("%d%d",&n,&m);
f[0] = 1;
for(int i = 1;i <= n;i ++) scanf("%d",&v[i]);
for(int i = 1;i <= n;i ++){
for(int j = v[i];j <= m;j ++){
f[j] += f[j - v[i]];
}
}
printf("%lld",f[m]);
return 0;
}
$$(共140行)$$
👍👍👍
QWQ
👍👍👍
想问一下,为什么会爆int?
从题目中似乎看不出来,我是打完发现爆int了
刚刚又看了一遍,不知道是不是看漏了什么
反正题目没说吧
是啊
### 一、重复组合公式
重复组合($Combination$ $With$ $Repetition$)是一种特殊的组合:从$n$个 [HTML_REMOVED][HTML_REMOVED]不同元素[HTML_REMOVED][HTML_REMOVED]中可重复地选取$r$个元素,不管其顺序合成一组,称为从$n$个元素中取$r$个元素的可重复组合。两个重复组合相同,当且仅当所取的元素相同且同一元素所取的次数相同。
[HTML_REMOVED][HTML_REMOVED]
定理[HTML_REMOVED][HTML_REMOVED]: 从$n$个不同的元素每次取出$r$个元素的允许重复 组合总数为:
$$\huge C_{n+r-1}^r$$
这个公式的证明有很多种方法,这里只选取最容易理解的方式进行证明:
把$n$种元素当成$n$个顺序摆放的盒子,$r$个完全相同的球,这样从$n$种元素中有重复取$r$个元素的方法就转化成,把$r$个同质球放入$n$个盒子的方法。
为什么可以这样呢?想一想,把一个球放到第$i$个盒子就相当于从$n$种元素中我们取的第$i$种元素,如果有多个球放在第$i$个盒子中,相当于从$n$个元素中重复了取了第$i$种元素。
空间中$n+1$条 ‘|’ 把空间分成$n$个盒子
举个例子$n=6$,也就是$6$个盒子
[HTML_REMOVED]
[HTML_REMOVED]
[HTML_REMOVED]
那么我们往里面放球用 $\bullet$ 表示
则有
[HTML_REMOVED]
[HTML_REMOVED]
我们发现,除去两边边界的 |
实际的摆放方法就是$n-1$个 | 和 $r$个 $\bullet$ 的不同摆放方式
所以共有$n+r-1$个位置
我们从中选择$r$个位置放上小球即可
因此得到公式
$$\huge C_{n+r-1}^{r}$$
### 二、利用公式估算数据范围
$$\LARGE C_{3000+15-1}^{15}=\frac{3014!}{15!\times 2999!}=\frac{3000\times 3001\times … \times 3014}{15!}$$,
显然要大于
int
的范围,如果此题数据为最坏情况,那么long long
也会爆掉。nbo
tql
从n个元素中取r个元素的可重复组合(r次抽取转变为1次抽取),有放回抽样,从n个里面有放回抽样,抽r次,重点在于放回,既然是放回,那抽r次是不是相当于要放回r-1次?(最后一次的放回对抽取结果无影响)那么问题就变成我再把r-1个放入n里面,然后一次抽取r个。