題目連結: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 }