题意:
给定 n
种面值的货币,每种货币可以选无数个
问:组成面值为 m
的货币共有多少种方案
思路:
这是一道 完全背包求方案数 的裸题,分析思路与上一题 AcWing 278. 数字组合 完全一致
一共有 n
个物品,每个物品有体积 vi
,价值 wi
,每个物品能够选无数次
求总体积恰好为 m
的 方案数
闫氏DP分析法
初始状态:f[0][0] = 1(前0
个物品选出总体积恰好是0
的方案数,显然为1
)
目标状态:f[n][m](求前n
个物品选出总体积恰好是m
的方案数)
注意本题方案数会爆 int ,需要开 long long 来存状态
关于 空间/时间优化 ,可以参考这篇 AcWing 278. 数字组合
时间复杂度:
O(n×m)
一维优化代码:
空间复杂度:O(m)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 3010;
ll dp[M];
int n, m;
int main()
{
cin>>n>>m;
dp[0] = 1;
for(int j=1;j<=m;++j) dp[j] = 0;
for(int i=1;i<=n;++i)
{
int v;
cin>>v;
for(int j=v;j<=m;++j)
{
dp[j] += dp[j-v];
}
}
cout<<dp[m]<<endl;
return 0;
}
二维朴素代码:
空间复杂度:O(n×m)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 20, M = 3010;
ll dp[N][M];
int n, m;
signed main()
{
cin>>n>>m;
dp[0][0] = 1;
for(int j=1;j<=m;++j) dp[0][j] = 0;
for(int i=1;i<=n;++i)
{
int v;
cin>>v;
for(int j=0;j<=m;++j)
{
if(j<v) dp[i][j] = dp[i-1][j];
else dp[i][j] = dp[i-1][j] + dp[i][j-v];
}
}
cout<<dp[n][m]<<endl;
return 0;
}