‘數字求和‘問題的總結

問題1:給定一個正整數N,求出和爲N的全部序列a1,a2, .., ak。其中,0< a1 < a2 < .. < ak < N

好比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

結束。

路漫漫其修遠兮,吾將上下而求索。

相關文章
相關標籤/搜索