• 母函数入门


    一篇写的很不错的博客链接:https://blog.csdn.net/xiaofei_it/article/details/17042651

    母函数通常解决类似如下的问题:

    给5张1元,4张2元,3张5元,要得到15元,有多少种组合?

    某些时候会规定至少使用3张1元、1张2元、0张5元。

    某些时候会规定有无数张1元、2元、5元。

    ……

    其实母函数的问题大部分也可以用dp/背包来写,但是我太弱了 感觉dp容易写错 有个母函数这样比较容易理解的模板更好。

    接下来是几道我母函数入门的题目:

    我这里都运用了last标记来优化母函数的效率,这样效率更高。

    HDU1085

    题意:面值分别为1,2,5的硬币,给出它们的数量。问不能组成的最小金额是多少。

    思路:母函数跑出金额为n的组合方案数有多少种,从1开始遍历,第一个方案数为 0 的n就是答案。

    代码:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<algorithm>
     4 #define mem(a, b) memset(a, b, sizeof(a))
     5 using namespace std;
     6 
     7 int val[5], num[5], last, last2;
     8 int temp[8100], ans[8100];
     9 
    10 int main()
    11 {
    12     val[0] = 1, val[1] = 2, val[2] = 5;
    13     while(scanf("%d%d%d", &num[0], &num[1], &num[2]) != EOF)
    14     {
    15         if(num[0] + num[1] + num[2] == 0)
    16             break;
    17         mem(ans, 0), mem(temp, 0);
    18         last = 0, ans[0] = 1;
    19         for(int i = 0; i < 3; i ++)
    20         {
    21             last2 = min(last + val[i] * num[i], 8100);
    22             memset(temp, 0, sizeof(int) * (last2 + 1));
    23             for(int j = 0; j <= num[i] && j * val[i] <= last2; j ++)
    24             {
    25                 for(int k = 0; k <= last && k + j * val[i] <= last2; k ++)
    26                     temp[k + j * val[i]] += ans[k];
    27             }
    28             memcpy(ans, temp, sizeof(int) * (last2 + 1));
    29             last = last2;
    30         }
    31         for(int i = 0; i <= 8010; i ++)
    32         {
    33             if(ans[i] == 0)
    34             {
    35                 printf("%d
    ", i);
    36                 break;
    37             }
    38         }
    39     }
    40     return 0;
    41 }
    HDU1085

    HDU2079

    题意:有k行,每行有两个整数a(1 <= a <= 8),b(1 <= b <= 10),表示学分为a的课有b门。输出一个整数,表示学n个学分的组合数。

    代码:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<algorithm>
     4 #define mem(a, b) memset(a, b, sizeof(a))
     5 using namespace std;
     6 
     7 int n, k;
     8 int val[10], num[10];
     9 int last, last2, temp[50], ans[50];
    10 
    11 int main()
    12 {
    13     int T;
    14     scanf("%d", &T);
    15     while(T --)
    16     {
    17         last = 0;
    18         mem(temp, 0), mem(ans, 0);
    19         ans[0] = 1;
    20         scanf("%d%d", &n, &k);
    21         for(int i = 0; i < k; i ++)
    22             scanf("%d%d", &val[i], &num[i]);
    23         for(int i = 0; i < k; i ++)
    24         {
    25             last2 = min(last + val[i] * num[i], n);
    26             memset(temp, 0, sizeof(int) * (last2 + 1));
    27             for(int j = 0; j <= num[i] && j * val[i] <= last2; j ++)
    28             {
    29                 for(int k = 0; k <= last && k + j * val[i] <= last2; k ++)
    30                 {
    31                     temp[k + j * val[i]] += ans[k];
    32                 }
    33             }
    34             memcpy(ans, temp, sizeof(int) * (last2 + 1));
    35             last = last2;
    36         }
    37         printf("%d
    ", ans[n]);
    38     }
    39     return 0;
    40 }
    HDU2079

    HDU2152

    题意:n种水果,求出m个水果的组合方案数。但是这里有数量限制,有下限跟上限

    代码:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<algorithm>
     4 #define mem(a, b) memset(a, b, sizeof(a))
     5 using namespace std;
     6 
     7 int n, m, down[110], up[110];
     8 int last, last2;
     9 int ans[110], temp[110];
    10 
    11 int main()
    12 {
    13     while(scanf("%d%d", &n, &m) != EOF)
    14     {
    15         for(int i = 0; i < n; i ++)
    16             scanf("%d%d", &down[i], &up[i]);
    17         mem(temp, 0), mem(ans, 0);
    18         ans[0] = 1, last = 0;
    19         for(int i = 0; i < n; i ++)
    20         {
    21             last2 = min(last + up[i], m);
    22             memset(temp, 0, sizeof(int) * (last2 + 1));
    23             for(int j = down[i]; j <= up[i] && j <= last2; j ++)
    24             {
    25                 for(int k = 0; k <= last && k + j <= last2; k ++)
    26                 {
    27                     temp[k + j] += ans[k];
    28                 }
    29             }
    30             memcpy(ans, temp, sizeof(int) * (last2 + 1));
    31             last = last2;
    32         }
    33         printf("%d
    ", ans[m]);
    34     }
    35     return 0;
    36 }
    HDU2152

    模板:

     1 ans[0] = 1, last = 0;  //初始化 多组输入的话还要 mem(ans, 0), mem(temp, 0) 
     2 for(int i = 0; i < k; i ++)
     3 {
     4     last2 = min(last + val[i] * num[i], n);//计算下一次的last 
     5     memset(temp, 0, sizeof(int) * (last2 + 1));//只清空temp[0...last2] 
     6     for(int j = down[i]; j <= up[i] && j * val[i] <= last2; j ++)//遍历因子中的每一项 注意数量限制 上下限 
     7     {
     8         for(int k = 0; k <= last && k + j * val[i] <= last2; k ++)//遍历答案数组,更新答案,因子乘之前因子相乘得到的临时答案 
     9         {//ans里是上一次的last,temp里是last2 
    10             temp[k + j * val[i]] += ans[k];
    11         }
    12     }
    13     memcpy(ans, temp, sizeof(int) * (last2 + 1));//temp赋值给ans 作为临时答案 待更新 
    14     last = last2;//更新last 
    15 }
  • 相关阅读:
    获取代理服务器ip列表的方法
    司机奖励新政策:失去的奖励还能再回来!
    成都Uber优步司机奖励政策(2月24日)
    北京Uber优步司机奖励政策(2月24日)
    滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(2月24日)
    成都Uber优步司机奖励政策(2月23日)
    北京Uber优步司机奖励政策(2月23日)
    滴滴快车奖励政策,高峰奖励,翻倍奖励,按成交率,指派单数分级(2月23日)
    Android Studio 模拟器启动问题——黑屏 死机 解决方法
    MYSQL使用mysqldump导出某个表的部分数据
  • 原文地址:https://www.cnblogs.com/yuanweidao/p/11233803.html
Copyright © 2020-2023  润新知