• HDU 1284(钱币兑换 背包/母函数)


    HDU 1028 相似的题目。

    方法一:完全背包。

    限制条件:硬币总值不超过 n。 

    目标:求出组合种数。

    令 dp[ i ][ j ] == x 表示用前 i 种硬币组合价值为 j 的钱共 x 种方法。

    状态转移方程:dp[ i ][ j ] = dp[ i - 1][ j ] + dp[ i ][ j - v[ i ] ] ;

    方程解释:用前 i 种硬币组合出钱 j 的方法数 = 前 i - 1 种硬币组合出钱 j 的方法数(不用第 i 种硬币)+ 至少用一枚第 i 种硬币的方法数。

    滚动数组实现,i 的这一维便可省去。

    代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 32769;
     4 int n,dp[maxn];
     5 void init()
     6 {
     7     memset(dp,0,sizeof(dp));
     8     dp[0] = 1;
     9     for(int i = 1; i <= 3; ++i)
    10         for(int j = i; j < maxn; ++j)
    11             dp[j] += dp[j-i];
    12 }
    13 int main()
    14 {
    15     init();
    16     while(~scanf("%d",&n))
    17         printf("%d
    ",dp[n]);
    18     return 0;
    19 }
    View Code

    方法二:母函数。

    用( 1 + x^k + x^(k*2) + x^(k*3) + ...) 表示参与组成的价值为 k 的硬币,1 表示硬币 k 个数为 0,每项前面的系数表示组成钱 k ( x 的次方数) 的方法数。

    比如现有 1 分,3 分,6 分的硬币各 1 枚,便可得到:

    ( 1 + x^1 ) * ( 1 + x^3 ) * ( 1 + x^6 ) = 1 + x^1 + x^3 + x^4 + x^6 + x^7 + x^9 + x^10;

    这表示用 1 分,3 分,6 分的硬币各 1 枚可以组合出钱数为 0,1,3,4,6,7,9,10 的方法各 1 种。

    若是 1 分,3 分,6 分的硬币各 2 枚的话,就可得到:

    ( 1 + x^1 + x^2 ) * ( 1 + x^3 + x^6 ) * ( 1 + x^6 + x^12 ) =

    1 + x^1 + x^2 + x^3 + x^4 + x^5 + 2*x^6 + 2*x^7 + 2*x^8 + x^9 + x^10 + x^11 + 2*x^12 + 2*x^13 + 2*x^14 + x^15 + x^16 + x^17 + x^18 + x^19 + x^20

    这表示用 1 分,3 分,6 分的硬币各 2 枚可以组合出

    钱数为 0 的方法 1 种,钱数为 1 的方法 1 种,钱数为 2 的方法 1 种,钱数为 3 的方法 1 种,钱数为 4 的方法 1 种,

    钱数为 5 的方法 1 种,钱数为 6 的方法 2 种,钱数为 7 的方法 2 种,钱数为 8 的方法 2 种,钱数为 9 的方法 1 种,

    钱数为 10 的方法 1 种,钱数为 11 的方法 1 种,钱数为 12 的方法 2 种,钱数为 13 的方法 2 种,钱数为 14 的方法 2 种,

    钱数为 15 的方法 1 种,钱数为 16 的方法 1 种,钱数为 17 的方法 1 种,钱数为 18 的方法 1 种,钱数为 19 的方法 1 种,

    钱数为 20 的方法 1 种。

    (神奇.......要了解更多关于母函数的问题请点这里

    手工模拟多项式展开,代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 32769;
     4 int n,ans[maxn],tans[maxn];
     5 void init()
     6 {
     7     for(int i = 0; i < maxn; ++i)
     8     {
     9         ans[i] = 1;
    10         tans[i] = 0;
    11     }
    12     for(int i = 2; i <= 3; ++i)
    13     {
    14         for(int j = 0; j < maxn; ++j)
    15             for(int k = 0; j+k < maxn; k+=i)
    16                 tans[j+k]+=ans[j];
    17         for(int j = 0; j < maxn; ++j)
    18         {
    19             ans[j] = tans[j];
    20             tans[j] = 0;
    21         }
    22     }
    23 }
    24 int main()
    25 {
    26     init();
    27     while(~scanf("%d",&n))
    28         printf("%d
    ",ans[n]);
    29     return 0;
    30 }
    View Code

    向这些博客的作者致谢:

    https://www.cnblogs.com/13224ACMer/p/4671551.html

    https://blog.csdn.net/u013480600/article/details/40477769

    https://blog.csdn.net/feizaoSYUACM/article/details/70040086

    https://blog.csdn.net/u010304217/article/details/38374417

    日后若能有更好的想法,再来完善。 希望看到的大神不吝赐教 orz
  • 相关阅读:
    直播平台的相关技术(转载)
    各种排序算法分析总结(待整理))
    算法:60.第k个排列
    三种随机化算法:舍伍德算法 拉斯维加斯算法 蒙特卡洛算法
    随机化算法之随机数
    caffe调试
    Euclideanloss_layer层解析
    布线问题(分支限界法)
    最大堆和最小堆
    机器学习知识框架
  • 原文地址:https://www.cnblogs.com/Taskr212/p/9561041.html
Copyright © 2020-2023  润新知