完全背包方案计数:外层按面值分层保证不重不漏,内层金额正序枚举允许面值无限复用,f[m] 即组合方案数。
OJ: roj
题目 ID: 1273
难度:普及-
标签:DP完全背包计数DP
创建: 2026-09-30 02:52
更新: 2026-10-05 07:44
题目描述
给定
输入:第一行
样例:
思路
完全背包计数。设
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-07-05 22:10
# update_at: 2026-07-05 22:10
import sys
def solve() -> None:
data = iter(map(int, sys.stdin.buffer.read().split()))
n, m = next(data), next(data) # n 种面值,目标金额 m
coins = [next(data) for _ in range(n)]
# f[j] = 恰好凑出面值 j 的方案数(组合计数,不区分顺序)
f = [1] + [0] * m # f[0] = 1:什么都不用是一种方案
for c in coins: # 每种面值只处理一遍 → 同一面值不区分排列顺序
for j in range(c, m + 1): # 正序扫:f[j] 可多次使用面值 c(完全背包)
f[j] += f[j - c]
print(f[m])
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-05 07:44
* update_at: 2026-10-05 07:44
*/
#include <iostream>
using namespace std;
const int MAXM = 10005;
const int MAXN = 105;
typedef long long ll;
ll n, m;
ll a[MAXN]; // 面值数组
ll f[MAXM]; // f[j] 表示凑出面值 j 的方案数
void read_input() {
cin >> n >> m;
for (ll i = 1; i <= n; i++) {
cin >> a[i];
}
}
void solve() {
f[0] = 1; // 什么都不选是一种方案
for (ll i = 1; i <= n; i++) { // 外层按面值分层,保证组合去重
ll c = a[i];
for (ll j = c; j <= m; j++) { // 金额正序枚举,面值可无限使用
f[j] += f[j - c];
}
}
cout << f[m] << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
read_input();
solve();
return 0;
}