60天备战省赛1——生成函数

来源:互联网 发布:网络教育拿学位证书 编辑:程序博客网 时间:2024/05/18 01:41

推荐博客: Tanky woo —-http://www.wutianqi.com/?p=596
这里的讲解非常不错,还有其他算法专题都很好。现在拿出模板核心代码进行注释

#include <iostream>using namespace std;// Author: Tanky Woo// www.wutianqi.comconst int _max = 10001; // c1是保存各项质量砝码可以组合的数目// c2是中间量,保存没一次的情况int c1[_max], c2[_max];   int main(){   //int n,i,j,k;    int nNum;   //     int i, j, k;    while(cin >> nNum)    {        for(i=0; i<=nNum; ++i)   // ---- ①        {            c1[i] = 1;            c2[i] = 0;        }        for(i=2; i<=nNum; ++i)   // ----- ②        {            for(j=0; j<=nNum; ++j)   // ----- ③                for(k=0; k+j<=nNum; k+=i)  // ---- ④                {                    c2[j+k] += c1[j];                }            for(j=0; j<=nNum; ++j)     // ---- ⑤            {                c1[j] = c2[j];                c2[j] = 0;            }        }        cout << c1[nNum] << endl;    }    return 0;}

首先确保你知道c数组的含义——它用来保存索引为nNum的拆分数!④⑤⑥
①对砝码下标进行初始化,置1。

②从第2个表达式开始,一直到第nNum个,因为如果求解nNum的拆分数的话,它所需要的最大砝码质量不会超过nNum本身。

③其实这一步计算机开始模拟人计算多项式展开的方法,可以自己先写一下,然后就会发现,这个j的代表的是计算过程中得到的最左边的,越来越长的这个表达式中的每个x^n项。
④因为那个生成函数的第i项的增量是i,而且k+j的值要小于所求的nNum所以条件以上的样子。
有必要说一下这个c2[j+k]=c1[j];理解它之前我忘记了c数组的含义所以不能明白。生成函数跟dp是有关系的,这个题在整数拆分的时候就有很多的重叠情况,使用生成函数的思想来计算,但是在划分时还是将它的解决方案划分成两部分。取质量为n的砝码和前一个状态。或者不取质量为n的砝码,保持之前的状态。

按照博客中推荐题目的顺序,前两个题自己立即以后看到第三个需要变化一下计算的方式。
第三个问题:本拉登那个题的变化在于它给的钱币不是无限数目的,而是确定增量(1,2,5)确定数目的,求解第一个不能用它们凑出的最小整数。
反映到生成函数模型中就是
g(x)=(1+x+x^2+…+x^num1*1)(1+x^2+x^4+…+x^num2*2)(1+x^5+x^10+…+x^num3*5)
接下来就是用两个数组来求解拆分数了,然后找到结果数组中值为零的第一个数字输出,或者输出x上标最大的那个就可以了。
如何计算这个多项式呢?

 for(int i=0; i<=num[1]; ++i)            c1[i] = 1;//初始化 for(int i=0; i<=num[1]; ++i)     for(int j=0; j<=num[2]*2; j+=2)//j指示x的指数增量为2的系数      c2[j+i] += c1[i];//求拆分数   for(int i=0; i<=num[2]*2+num[1]*1; ++i)          {      c1[i] = c2[i];      c2[i] = 0;   }//以上代码片是用来计算g(x)前两个表达式的拆分数的,同理,tanky woo大牛的代码中后半部分合并这个结果和第三个表达式。
1 0
原创粉丝点击