HDU 1028 Ignatius and the Princess III:dp or 母函数
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1028
题意:
给你一个正整数n,将n拆分成若干个正整数之和,问你有多少种方案。
注:"4 = 3 + 1"和"4 = 1 + 3"视为同一种方案。(加数是无序的)
题解1(dp):
表示状态:
dp[n][m] = num of methods
表示用均不超过m的元素组成n的方法数。
如何转移:
假设当前状态为dp[n][m].
对于等于m的元素,有两种决策。要么不用,要么用。
(1)不用:dp[n][m] += dp[n][m-1]
(2)用: dp[n][m] += dp[n-m][m]
综上:dp[n][m] = dp[n][m-1] + dp[n-m][m]
找出答案:
ans = dp[n][n]
边界条件:
dp[0][i] = 1 (0<=i<=MAX_N)
题解2(母函数):
要凑出n,每种方案无非是取几个1,几个2,几个3......
这就是母函数的经典问题啦(取硬币)。
构造母函数:
G(x) = (1 + x^1 + x^2 + x^3...) * (1 + x^2 + x^4 + x^6...) * (1 + x^3 + x^6 + x^9...) * (1 + x^4 + x^8 + x^12...)...
找出答案:
x^n项的系数即为答案。
AC Code(dp):
1 // dp[n][m] = num of methods 2 // n: the elems are up to n 3 // m: each elem won't be not more than m 4 // dp[n][m] = dp[n][m-1] + dp[n-m][m] 5 // ans = dp[n][n] 6 // dp[0][m] = 1 7 8 #include <iostream> 9 #include <stdio.h> 10 #include <string.h> 11 #define MAX_N 125 12 13 using namespace std; 14 15 int n; 16 int dp[MAX_N][MAX_N]; 17 18 void cal_dp() 19 { 20 memset(dp,0,sizeof(dp)); 21 for(int i=0;i<MAX_N;i++) 22 { 23 dp[0][i]=1; 24 } 25 for(int i=1;i<MAX_N;i++) 26 { 27 for(int j=1;j<MAX_N;j++) 28 { 29 if(i>=j) dp[i][j]=dp[i][j-1]+dp[i-j][j]; 30 else dp[i][j]=dp[i][i]; 31 } 32 } 33 } 34 35 int main() 36 { 37 cal_dp(); 38 while(cin>>n) 39 { 40 cout<<dp[n][n]<<endl; 41 } 42 }
AC Code(Generating Function):
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define MAX_N 125 5 6 using namespace std; 7 8 int n; 9 int ans[MAX_N]; 10 int temp[MAX_N]; 11 12 void generating_function(int n) 13 { 14 memset(ans,0,sizeof(ans)); 15 ans[0]=1; 16 for(int i=1;i<=n;i++) 17 { 18 memset(temp,0,sizeof(temp)); 19 for(int j=0;j*i<=n;j++) 20 { 21 for(int k=0;k+j*i<=n;k++) 22 { 23 temp[k+j*i]+=ans[k]; 24 } 25 } 26 memcpy(ans,temp,sizeof(temp)); 27 } 28 } 29 30 int main() 31 { 32 generating_function(120); 33 while(cin>>n) 34 { 35 cout<<ans[n]<<endl; 36 } 37 }