好比5 = 1+4 = 2+3 算法
问题2:有正整数 N, 可表示为a1+a2+a3+...+aK=N;而且 0<a1<a2<...<aK; 求,一共有多少种表示法。.net
(在此,我自我检讨下:没通过思考,起初想固然的认为2和1有同样的复杂度,简直太弱了!)code
问题1的解法是利用递归回溯。关键在于定义一个f(n,k),其中n表示须要求的和,k表示容许的最大ai。此回溯算法的出口有两个:一个是找到合适的序列;一个是子问题遍历完成。递归
算法主要代码以下:get
void f(int n, int k) { if (n == 0) { print_result(); count++; return ; } int max, min; max = (n<k)? n : (k); min = sqrt(2*n) - 1; min = (min < 1)?1:min; for (int i=max; i>=min; --i) { if ( !(n-i >= 0) ) continue; a[i] = 1; f(n-i, i-1); a[i] = 0; } }
初始调用是f(N, N-1) //计算和为N的整数序列,ai最大不能超过N-1it
第二个问题使用动态规划法,时间复杂度是N^2.class
主要思想是定义一个f[N+1][N+1],最后计算F[N][N-1].其中F[n][k]表示,和为n,ai最大是k的序列数。遍历
因而,就有im
F[n][k] = F[n][k-1] + F[n-k][k-1] (k < n)动态规划
F[n][k] = F[n][n-1] + 1 (k>=n)
边界条件F[0][0] = 1;
主要代码以下:
for (int n=0; n<N+1; n++) for (int k=0; k<N+1; k++) { if (k==0) f[n][k] = 0; else if (k<n) f[n][k] = f[n][k-1] + f[n-k][k-1]; else if (k>=n) f[n][k] = f[n][n-1] + 1; else { printf("we should never get here!\n"); exit(-1); } }
因为每一步的操做试试O(1)的加法,因此总的running time是O(N^2).
感谢OSC的几位朋友, @zzz2012 @中山野鬼 @看能不能改个名 (哥们,打你的名字真不容易,我还特意查了下)
尤为是@zzz2012
结束。
路漫漫其修远兮,吾将上下而求索。