一、问题描述:
有 V 种面值的货币,求组成面值 N 的货币有多少种方案。
二、解决方案:
该问题实际是一个最大化的问题,用自底向上的方式求最有解。如果问题规模较大,考虑高精度计算。
假设有3种货币,面值分别为1,2,5,组成面值为10的货币。
把第 1 种货币组成面值为 j 的方案数作为第一阶段,把前 2 种货币组成面值为 j 的方案数作为第二阶段,
⋯
⋯
\cdots \cdots
⋯⋯,把前 V 种货币组成面值为 j 的方案数作为第V阶段。第一阶段初始值均为1。
动态转移方程:
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
+
f
[
i
]
[
j
−
v
a
l
u
e
[
i
]
]
f[i][j] = f[i-1][j] + f[i][j-value[i]]
f[i][j]=f[i−1][j]+f[i][j−value[i]]
(
1
≤
i
≤
V
,
0
≤
j
≤
N
)
(1\leq i \leq V,0 \leq j \leq N)
(1≤i≤V,0≤j≤N)
三、代码:
方法一:
// TSWorld
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const long long MAXX = 100;
int main()
{
int V = 0,N = 0;
int value[MAXX] = {0};
int f[MAXX][MAXX] = {0};
cin>>V>>N;
for(int i = 1;i <= V;i++)
cin>>value[i];
for(int i = 0;i <= N;i++)
f[1][i] = 1;
for(int i = 2;i <= V;i++) {
for(int j = 0;j <= N;j++) {
if(j >= value[i])
f[i][j] = f[i-1][j] + f[i][j-value[i]];
else
f[i][j] = f[i-1][j];
}
}
cout<<f[V][N]<<endl;
return 0;
}
方法二:
因为程序在循环滚动计算,所以可以简化为一维数组:
f
[
j
]
=
f
[
j
]
+
f
[
j
−
p
]
f[j] = f[j] + f[j-p]
f[j]=f[j]+f[j−p]
// TSWorld
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const long long MAXX = 100;
int main()
{
int V = 0,N = 0;
int value[MAXX] = {0};
int f[MAXX] = {0};
cin>>V>>N;
for(int i = 1;i <= V;i++)
cin>>value[i];
f[0] = 1;
for(int i = 1;i <= V;i++) {
for(int j = value[i];j <= N;j++)
f[j] += f[j-value[i]];
}
cout<<f[N]<<endl;
return 0;
}