母函数 经典题目汇总
HDU 1398 Square Coins(普通母函数 || 完全背包)
题意:
可选钱 种类17种,值分别为 i*i(i>=1&&i<=17)
求组和之和=钱数K的方案数
分析:
方法一:
///DP 完全背包问题(求装入背包) ///f[i]表示 ///打表 #include<stdio.h> int main() { int a[20]={0,1,4,9,16,25,36,49,64,81,100,121,144,169,196,225,256,289},f[305]={0}; int i,n,j; f[0]=1; for(i=1;i<=17;i++)///第几种钱 for(j=a[i];j<=300;j++)/// f[j]+=f[j-a[i]]; while(scanf("%d",&n)!=EOF){ if(n==0) break; printf("%d\n",f[n]); } return 0; }
方法二:
母函数
母函数应用于——————形式上说,普通型生成函数用于解决多重集的组合问题,而指数型母函数用于解决多重集的排列问题.。现在我们先讨论普通生成函数;
这里组合问题,用普通母函数
#include "cstdio" #define N 305 int c1[N];///记录各次幂系数 int c2[N];///记录中间计算结果 void solve() { for(int i=0;i<=300;i++)///初始化(第一个表达式) { c1[i]=1; c2[i]=0; } for(int i=2;i<=17;i++)///那个表达式 { for(int j=0;j<=300;j++) { for(int k=0;k+j<=300;k+=i*i)///此表达式中各项的次幂 { ///(把组合问题的加法法则和幂级数的乘幂对应起来) c2[j+k]+=c1[j]; } } for(int j=0;j<=300;j++) { c1[j]=c2[j]; c2[j]=0; } } } int main() { int n; solve(); while(~scanf("%d",&n),n) { printf("%d\n",c1[n]); } return 0; }
HDU1028
Ignatius and the Princess III
题意:
输入一数N,求1-N N种数,任意组合(数不一定都出现和个数任意)之和=N的方案个数
分析:
组合问题
普通母函数
#include "cstdio" #define N 305 int c1[N]; int c2[N]; void solve() { for(int i=0;i<=120;i++) { c1[i]=1; c2[i]=0; } for(int i=2;i<=120;i++) { for(int j=0;j<=120;j++) { for(int k=0;k+j<=120;k+=i) { c2[k+j]+=c1[j]; } } for(int j=0;j<=120;j++) { c1[j]=c2[j]; c2[j]=0; } } } int main() { int n; solve(); while(scanf("%d",&n)!=EOF) { printf("%d\n",c1[n]); } }
HDU1085
题意:1 2 5三种数,你赋予他们数量,求他们组成和不能组成的最小数
个数有限
#include "cstdio" #include "iostream" #include "cstring" using namespace std; #define N 10000 int c1[N]; int c2[N]; int num[4]; int Max; void solve() { num[1]*=2;num[2]*=5; Max=num[0]+num[1]+num[2]; memset(c1,0,sizeof(c1)); memset(c2,0,sizeof(c2)); for(int i=0;i<=num[0];i++) { c1[i]=1; } for(int j=0;j<=num[0];j++) for(int k=0;k+j<=num[0]+num[1];k+=2) c2[k+j]+=c1[j]; for(int i=0;i<=num[0]+num[1];i++) { c1[i]=c2[i];c2[i]=0; } for(int j=0;j<=num[0]+num[1];j++) for(int k=0;k+j<=num[0]+num[1]+num[2];k+=5) c2[k+j]+=c1[j]; for(int i=0;i<=num[0]+num[1]+num[2];i++) { c1[i]=c2[i];c2[i]=0; } } int main() { while(scanf("%d%d%d",&num[0],&num[1],&num[2])!=EOF&&(num[0]||num[1]||num[2])) { solve(); int i; for(i=0;i<=Max;i++) { if(c1[i]==0) { printf("%d\n",i); break; } } if(i==Max+1) printf("%d\n",i); } }