母函数

来源:互联网 发布:python高级编程 豆瓣 编辑:程序博客网 时间:2024/04/28 12:00

母函数即生成函数,有普通型生成函数和指数型生成函数两种,常用于组合数学中求某个问题的方法数。

例:G(x) = a0 + a1x + a2x*2 + a3x^3 +....+ anx^n

其中ai表示i的组合

 

应用例如:

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

(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

 

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

整数拆分成若干整数的和,办法不一,不同拆分法的总数叫做拆分数

 

 

hdu 1028  Ignatius and the Princess III

http://acm.hdu.edu.cn/showproblem.php?pid=1028

 

 

给定一个的数,拆分成由(1, 2, 3.。。。。。。)中任意几个所组成的,问有多少种拆分方法~

 

#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int maxn= 130;int n;int c1[maxn], c2[maxn];void handle(){    int i, j, k, t;    memset( c2, 0, sizeof( c2));    for( i=0; i<=n; i++)//第一项 即(1+ x + x2 + x3 +……)        c1[i]= 1;    for( i=2; i<=n; i++){ //枚举2到n项        for( j=0; j<=n; j++)//枚举每一位系数,即所求系数            for( k=0; k+j<=n; k+=i)//枚举每一项中的各位,k+=i~~~                c2[j+k]+= c1[j];        for( j=0; j<=n; j++){            c1[j]= c2[j];            c2[j]= 0;        }    }}int main(){  //  freopen("1,txt", "r", stdin);    while( scanf("%d", &n) != EOF){        handle();        printf("%d\n", c1[n]);    }    return 0;}


Square CoinsSquare Coins hdu 1398

http://acm.hdu.edu.cn/showproblem.php?pid=1398

 

钱币的价值为1^2, 2^2......17^2,问是否组合可得某价值

 

#include <iostream>#include <cstdio>#include <cmath>#include <queue>#include <cstring>using namespace std;const int maxn= 500;int c1[maxn], c2[maxn];int w[20];int n;void handle(){    int i, j, k, t;    memset( c2, 0, sizeof( c2));    for( i=0; i<=n; i++)        c1[i]= 1;    for( i=2; i<=17; i++){        for( j=0; j<=n; j++)            for( k=0; k+j<=n; k+= w[i])                c2[j+k]+= c1[j];        for( j=0; j<=n; j++){            c1[j]= c2[j];            c2[j]= 0;        }    }}int main(){   // freopen("1.txt", "r", stdin);    int i;    for(i=1; i<=17; i++)        w[i]= i*i;    while( scanf("%d", &n) && n){        handle();        printf("%d\n", c1[n]);    }    return 0;}


 

 

 

hdu 1085 Holding Bin-Laden Captive!

http://acm.hdu.edu.cn/showproblem.php?pid=1085

此题背包也可,或直接计算器特殊情况

 

 

有1,2,5三种面值的钱币,各有一定数量,问最小的不能得到的组合值是多少

 

#include <iostream>#include <cstdio>#include <cmath>#include <queue>#include <cstring>using namespace std;const int maxn= 1000000;int c1[maxn], c2[maxn], a[3], v[3]={1, 2, 5};int n;void handle(int cnt){    int i, j, k, t;    memset( c1, 0, sizeof( c1));    memset( c2, 0, sizeof( c2));    for( i=0; i<= a[0]; i++)        c1[i]= 1;    for( i=1; i<=2; i++){             for( j=0; j<=cnt ; j++){            for( k=0, t= 0; k+j <= cnt && t<= a[i]; k+= v[i], t++)                c2[j+k]+= c1[j];        }        for( j= 0; j<= cnt; j++){            c1[j]= c2[j];            c2[j]= 0;        }    }}int main(){   // freopen("1.txt", "r", stdin);    int i;    while( scanf("%d%d%d", &a[0], &a[1], &a[2]) && !( a[0]==0 && a[1]==0 && a[2]==0)){        n= a[0] + v[1]*a[1] + v[2]*a[2];        handle( n+1);        for( i=1; i<=n+1; i++)            if( c1[i]== 0){                printf("%d\n", i);                break;            }    }    return 0;}


 

hdu 1059 Dividing

 

http://acm.hdu.edu.cn/showproblem.php?pid=1059

 

同样是可以有分组背包做

 

 

有1~6种价值的物品,分别有一定数量,问可否平分

 

计算ans/2系数是否为0

主要对ans/2直接处理会超时,由于60为1, 2, 3, 4, 5 ,6的最小公倍数,所以ans对60取余后,再对ans/2处理

 

#include <iostream>#include <cstdio>#include <cmath>#include <queue>#include <cstring>using namespace std;const int maxn= 60005;int c1[maxn], c2[maxn];int n, w[10]={1, 2, 3, 4, 5, 6};int num[10], ans;void handle(){    int i, j, k;    memset( c2, 0, sizeof( c2));    memset( c1, 0, sizeof( c1));    for( i=0; i<=ans/2 && i<=num[0]; i++) //注意可取个数        c1[i]= 1;    for( i=1; i<=5; i++){ //枚举有多少项, 1+x1+x2+x3... 为一项        for( j=0; j<=ans/2; j++) //j数组存储为每一位的系数,下标为权值,即x0, x1, x2。。。时的方法数            for( k=0; k*w[i]+j<=ans/2 && k<=num[i];  k++) //这里注意,k表示的是数量,不要与权值弄混                c2[k*w[i]+j]+= c1[j];  //c的下标为权值,故用k*w[i],存储值为方法数        for( j=0; j<=ans/2; j++){            c1[j]= c2[j];            c2[j]= 0;        }    }}int main(){    //freopen("1.txt", "r", stdin);    int i, j, k, text=1;    while( scanf("%d%d%d%d%d%d", &num[0], &num[1], &num[2], &num[3], &num[4], &num[5]) && !(num[0]==0 && num[1]==0 && num[2]==0 && num[3]==0 && num[4]==0 && num[5]==0)){        printf("Collection #%d:\n", text++);        for( i=0, ans= 0; i<=5; i++)            ans+= w[i] * num[i];        if( ans%2 != 0) {            printf("Can't be divided.\n\n");            continue;        }        ans%= 60;        handle();        if( c1[ans/2]!= 0) printf("Can be divided.\n\n");        else printf("Can't be divided.\n\n");    }    return 0;}


 

 

原创粉丝点击