母函数

来源:互联网 发布:ubuntu vi复制命令 编辑:程序博客网 时间:2024/04/28 07:47

                      

有1克、2克、3克、4克的砝码各一枚,能称出哪几种重量?每种重量各有几种可能方案? 

考虑用母函数来接吻这个问题:

我们假设x表示砝码,x的指数表示砝码的重量,这样:

1个1克的砝码可以用函数1+x表示,

1个2克的砝码可以用函数1+x2表示,

1个3克的砝码可以用函数1+x3表示,

1个4克的砝码可以用函数1+x4表示,

几种砝码的组合可以称重的情况,可以用以上几个函数的乘积表示:

(1+x)(1+x2)(1+x3)(1+x4)

=(1+x+x2+x3)(1+x3+x4+x7)

=1+x+x2+2x3+2x4+2x5+2x6+2x7+x8+x9+x10 

从上面的函数知道:可称出从1克到10克,系数便是方案数。(!!!经典!!!)

    例如右端有2x5 项,即称出5克的方案有2:5=3+2=4+1;同样,6=1+2+3=4+2;10=1+2+3+4。

 

 

 

 

 

 

 

  1. 整数拆分

输入一个整数n,把它拆成若干个整数相加,输出有多少种拆分的方法。

比如:4=3+1=2+2=2+1+1=1+1+1+1,有5种。

 

解:

所谓整数拆分即把整数分解成若干整数的和(相当于把n个无区别的球放到n个无标志的盒子,盒子允许空,也允许放多于一个球)。

 

G(x)=(1+x+x^2+…)(1+x^2+x^4+…)(1+x^3+x^6+…)…

 

#include <stdio.h>

#include <string.h>

int main()

{

    int c1[200],c2[200];     //c1保存当前表达式里各项的系数,c2是中间量

    int n,i,j,k;

    while(scanf("%d",&n)!=EOF)  

    {

        for(i=0;i<=n;i++)   //n拆分的数必定小于或等于n,所以只用从0遍历到n,即母函数的第1个括号里的表达式只能是1+x+x^2+…+x^n

        {

            c1[i]=1;          //初始化c1[],c1[]的下标是项的指数,值是项的系数

            c2[i]=0;

        }

        for(i=2;i<=n;i++)       //后面有n-1个表达式(括号里的式子),要展开n-1次,i指第i个表达式

        {

            for(j=0;j<=n;j++)

            {

                for (k=0;k+j<=n;k=k+i)

                {

                    c2[k+j]+=c1[j];        //只用保留指数<=n的项,所以k+j<=n

                }                        //j指当前表达式里项的第j个项,k指后一个表达式里项的指数,k=k+i

            }                            //两个相邻表达式展开

            for(j=0;j<=n;j++)

            {

                c1[j]=c2[j];

                c2[j]=0;

            }            //每展开一次,就将c1[]更新,c2[]归0

        }

        printf("%d\n",c1[n]);

    }

    return 0;

}

 

  1. 钱币组合:

有面值为1,2,5的3种硬币,输入各硬币的个数,求最小的一个不能组合的成的价值。

比如输入1 1 3,输出4

 

解:

G(x)=(1+x+x^2+…)(1+x^2+x^4+…)(1+x^5+x^10+…)

3种面值,所以只有3个括号表达式。

 

#include <stdio.h>#include <string.h>int main(){    int a,b,c,i,j,k,sum;    int c1[8008],c2[8008];    int elem[3]={1,2,5};    int num[4];    while(scanf("%d%d%d",&a,&b,&c)!=EOF)    {        if(a==0&&b==0&&c==0)            break;        sum=1*a+2*b+5*c;        num[1]=a;        num[2]=b;        num[3]=c;     //num[]存放括号内表达式的项的个数         memset(c1,0,sizeof(c1));        memset(c2,0,sizeof(c2));     //c1[],c2[]全部归0        for(i=0;i<=a;i=i+elem[0])    //初始化第1个表达式里各项的系数            c1[i]=1;            for(i=2;i<=3;i++)        {            for(j=0;j<=sum;j++)            {                for(k=0;k<=num[i]*elem[i-1]&&k+j<=sum;k=k+elem[i-1])                {                    c2[j+k]+=c1[j];                }            }            for(j=0;j<=sum+1;j++)            {                c1[j]=c2[j];                c2[j]=0;            }        }                for(i=0;i<=sum+1;i++)        {            if(c1[i]==0)            {                printf("%d\n",i);                break;            }        }    }    return 0;}


 

原创粉丝点击