题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1163
解题报告:
将整数N分解为:两个及以上的不重复的整数,最流行的解法是动态规划,和生成函数(01背包思路)。
将问题看成经典的搭积木的问题。相当与求:将N块积木搭成J排.
f[i,j] = f[i,j-1]+ f[i-j,j-1];
初始化f[0,0] = 1;
即求f[N,N] - 1;(两个及以上的)
#include <stdio.h> #include <algorithm> #include <string.h> #define MAX 505 using namespace std; long long dp[MAX][MAX]; int main() { /*memset(dp,0,sizeof(dp)); dp[0] = 1; for(int i=1; i<MAX; i++) for(int j=MAX-1; j>=i; j--) dp[j] += dp[j-i];*/ int n; dp[0][0]=1; for(int i=0; i<MAX; i++) { for(int j=1; j<=i; j++) dp[i][j]=dp[i][j-1]+dp[i-j][j-1]; for(int j=i+1; j<MAX; j++) dp[i][j]=dp[i][i]; } while(scanf("%d",&n),n) printf("%lld ",dp[n][n]-1); return 0; }
生成函数算法,这里的知识是离散数学中的母函数。
G(X) = (1+X)(1+X^2)(1+X^3)***(1+X^N);
这里可以看出x^3的系数为 X*X^2, 和X^3,因为这里的拆数是拆成两个及以上,所以减去X^3,及要减1;
f[j]表示x^j的系数,那么计算x^j的系数,是要累加的,这里采用01背包,f[j] += f[j-i];(i=1~0(j=i))
memset(dp,0,sizeof(dp)); dp[0] = 1; for(int i=1; i<MAX; i++) for(int j=MAX-1; j>=i; j--) dp[j] += dp[j-i]; printf("%d ",dp[n]-1);