1. 程式人生 > >簡單整數劃分(遞迴法+動態規劃法)

簡單整數劃分(遞迴法+動態規劃法)

整數劃分:

所謂整數劃分,就是將一個數n寫成正整數相加的形式,如3可以劃分為1+1+1,1+2,3等三種情況,而f(n,m)則表示,劃分數中最大的數小於m時n的劃分。如f(3,2)就是1+1+1,1+2兩種。

遞迴法:

根據n和m的情況,有如下幾種情況

1.當n == 1或m == 1時,都只有一種劃分,其中n==1時,只有一種劃分{1},只有m == 1時,只有一種劃分{1,1,1.....,1};即n個1。

2.由於劃分中沒有負數,所以當n < 1或m < 1時,都只有0種劃分。

3.當n < m時,由於沒有負數,所以f(n,m)就相當於f(n,n);

4.當n == m時,可以分為兩種情況:

(1).劃分中有n即只有{n}一種情況。

(2).劃分中沒有n即劃分中最大值小於等於n-1,即n對於n-1的所有劃分。

所以綜上,n == m時,f(n,n) == f(n,n-1)+1;

5.當n > m時,可以分為兩種情況:

(1).劃分中包含最大值m的情況,即{m,{x1,x2.....}},而在{x1,x2.....},也就是n-m中同樣可能大於m,所以為n-m對於m的劃分,即f(n-m,m);

(2).劃分中不包含m,同情況4,所有值比m小,即f(n,m-1);

綜上,f(n-m,m)+f(n,m-1)。

程式碼如下:

#include <bits/stdc++.h>
using namespace std;
int query(int n,int m)
{
    if(n == 1||m == 1)  return 1;
    if(n < 1||m < 1)    return 0;
    if(n < m)   return query(n,n);
    if(n == m)  return query(n,m-1)+1;
    if(n > m)   return query(n-m,m)+query(n,m-1);
}

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        cout<<"遞迴:"<<query(n,n)<<endl;
    }
    return 0;
}

動態規劃法:

在遞迴法中的1,2情況都可以直接通過初始化dp陣列來進行處理,而情況3,4,5則轉換成動態轉移方程就可以了。

轉移方程:dp[n][m] += dp[i][j-1]+dp[i-j][j];

(當i-j < j時)dp[n][m] += dp[i][j-1]+dp[i-j][i-j];

#include <bits/stdc++.h>
using namespace std;
const int N = 100;
int main()
{
    int n;
    int dp[550][550];
    dp[1][1] = 1;
    for(int i = 2;i <= N; i++){dp[i][1] = 1;dp[i][i] = 1;}

    for(int i = 2;i <= N; i++)
    {
        for(int j = 2;j <= i; j++)
        {
            if(i-j < j) dp[i][j] += dp[i][j-1]+dp[i-j][i-j];
            else dp[i][j] += dp[i][j-1]+dp[i-j][j];
        }
    }
    while(~scanf("%d",&n))
        cout<<"dp:"<<dp[n][n]<<endl;
    return 0;
}