USACO 2.3.4 Money Systems 货币系统(完全背包)

Description

母牛们不但创建了他们自己的政府而且选择了建立了自己的货币系统。 [In their own rebellious way],,他们对货币的数值感到好奇。 传统地,一个货币系统是由1,5,10,20 或 25,50, 和 100的单位面值组成的。 母牛想知道有多少种不同的方法来用货币系统中的货币来构造一个确定的数值。 举例来说, 使用一个货币系统 {1,2,5,10,...}产生 18单位面值的一些可能的方法是:18x1, 9x2, 8x2+2x1, 3x5+2+1,等等其它。 写一个程序来计算有多少种方法用给定的货币系统来构造一定数量的面值。 保证总数将会适合long long (C/C++) 和 Int64 (Free Pascal)。

Input

货币系统中货币的种类数目是 V 。 (1<= V<=25) 要构造的数量钱是 N 。 (1<= N<=10,000) 第 1 行: 二整数, V 和 N 第 2 ..V+1行: 可用的货币 V 个整数 (每行一个 每行没有其它的数)。

Output

单独的一行包含那个可能的构造的方案数。

Sample Input

3 10
1 2 5

Sample Output

10

解题思路:我上来一直觉得这是一道搜索题,用DFS写了一下,果然时间超限,其实这是一道完全背包的变形。

dp[i][j]表示前i种货币构成钱j的方法数,用a记录货币的面值,状态转移方程为:
dp[i][j]=dp[i-1][j]; ///不用第i种货币
dp[i][j]=dp[i-1][j]+dp[i][j-a[i]] ///当j>=a[i]时,用第i种货币

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define MAX 10010
 5 #define ll long long int
 6 using namespace std;
 7 int a[30];
 8 ll dp[30][MAX];
 9 int main()
10 {
11     int m,n;
12     int i,j;
13     scanf("%d%d",&n,&m);
14     for(i=1;i<=n;i++)
15     {
16         scanf("%d",&a[i]);
17         dp[i][a[i]]=1;
18     }
19     for(i=1;i<=n;i++)
20     {
21         for(j=1;j<=m;j++)
22         {
23             if(j>a[i])
24             {
25                 dp[i][j]=dp[i][j-a[i]]+dp[i-1][j];
26             }
27             else
28             {
29                 dp[i][j]=dp[i][j]+dp[i-1][j];
30             }
31         }
32     }
33     printf("%lld
",dp[n][m]);
34     return 0;
35 }

 优化为一维滚动数组之后:

 1 for(i=1;i<=n;i++)
 2 {
 3     scanf("%d",&a[i]);
 4 }
 5 dp[0]=1;
 6 for(i=1;i<=n;i++)
 7 {
 8     for(j=a[i];j<=m;j++)
 9     {
10         dp[j]=dp[j]+dp[j-a[i]];
11     }
12 }
13 printf("%lld
",dp[m]);
原文地址:https://www.cnblogs.com/wkfvawl/p/9714978.html