给定 V 种货币(单位:元),每种货币使用的次数不限。
不同种类的货币,面值可能是相同的。
现在,要你用这 V 种货币凑出 N 元钱,请问共有多少种不同的凑法。
输入格式
第一行包含两个整数 V 和 N。
接下来的若干行,将一共输出 V 个整数,每个整数表示一种货币的面值。
输出格式
输出一个整数,表示所求总方案数。
数据范围
1≤V≤25,
1≤N≤10000
输入样例:
3 10
1 2 5
输出样例:
10
分析:(借鉴别人)
状态表示: f[i][j]
表示 从前i种货币中选,且总价值恰好为j的所有选法集合的方案数。
那么f[n][m]
就表示表示 从前n种货币中选,且总价值恰好为m的所有选法集合的方案数,即为答案。
集合划分:
按照第i种货币可以选 0个,1个,2个,3个……k
个划分集合 f[i][j]
。其中k*w[i] <= j
,也就是说在背包能装下的情况下,枚举第i种货币可以选择几个。
状态计算:
f[i][j] = f[i-1][j]+f[i-1][j-w[i]]+f[i-1][j-2*w[i]],,,,,,+f[i-1][j-k*w[i]]
答案:
#include <iostream>
#include<bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
const int N = 1e4 + 10;
const int M = 30;
using namespace std;
//int v[N];
ll w[M];
ll dp[M][N];
int main()
{
ll n,m;
cin>>n>>m;
for(ll i=1;i<=n;i++){
cin>>w[i];
}
dp[0][0]=1;
for(ll i=1;i<=n;i++){
for(ll j=0;j<=m;j++){
for(ll k=0;k*w[i]<=j;k++){
dp[i][j]+=dp[i-1][j-k*w[i]];
}
}
}
cout<<dp[n][m]<<endl;
return 0;
}
优化:
一维DP
考虑优化
v代表第i件物品的体积
f[i][j] = f[i-1][j] + f[i-1][j-v]+f[i-1][j-2v]+……+f[i-1][j-kv])
f[i][j-v] = f[i-1,[j-v]+f[i-1][j-2v]+……+f[i-1][j-kv])
因此:
f[i][j] = f[i-1][j]+f[i][j-v])
状态计算为: f[j] = f[j] + f[j-v]
#include <iostream>
#include<bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
const int N = 1e4 + 10;
const int M = 30;
using namespace std;
//int v[N];
//ll w[M];
ll dp[N];
int main()
{
ll n,m;
cin>>n>>m;
dp[0]=1;
for(int i=1;i<=n;i++){
int k;
cin>>k;
for(int j=k;j<=m;j++){
dp[j]+=dp[j-k]; ///状态方程
}
}
cout<<dp[m]<<endl;
return 0;
}