dp整數劃分問題——03:複雜的整數劃分問題

整數劃分 :
  這道好題求:
  1. 將n劃分成若干正整數之和的劃分數。
  2. 將n劃分成k個正整數之和的劃分數。
  3. 將n劃分成最大數不超過k的劃分數。
  4. 將n劃分成若干奇正整數之和的劃分數。
  5. 將n劃分成若干不同整數之和的劃分數。

 

1.若劃分的多個整數可以相同

  設dp[i][j]爲將i劃分爲不大於j的劃分數

  (1) 當i<j時,i不能劃分爲大於i的數,所以dp[i][j]=dp[i][i]

  (2) 當i>j時,可以根據劃分中是否含有j分爲兩種情況。

                                    若劃分中含有j,劃分方案數爲dp[i-j][j]

                                    若劃分數中不含j,相當於將i劃分爲不大於j-1的劃分數,爲dp[i][j-1]

                            所以當i>jdp[i][j]=dp[i-j][j]+dp[i][j-1]

  (3) 當i=j時,也分爲兩種情況:

                                     若劃分中含有j只有一種情況,

                                     若劃分中不含j相當於將i劃分爲不大於j-1的劃分數。

                           此時dp[i][j]=1+dp[i][j-1]。


2.若劃分的正整數必須不同

  設dp[i][j]爲將i劃分爲不超過j的不同整數的劃分數

  (1) 當i<j時,i不能劃分爲大於i的數,所以dp[i][j]=dp[i][i]

  (2) 當i>j時,可以根據劃分中是否含有j分爲兩種情況。

                                   若劃分中含有j,則其餘的劃分中最大隻能是j-1,方案數爲dp[i-j][j-1]

                                   若劃分中不含j,相當於將i劃分爲不大於j-1的劃分數,爲dp[i][j-1]

                            所以當i>jdp[i][j]=dp[i-j][j-1]+dp[i][j-1]

  (3) 當i=j時,兩種情況:

                                   若劃分中含有j只有一種情況;

                                   若劃分中不含j相當於將i劃分爲不大於j-1的劃分數。

                           此時dp[i][j]=1+dp[i][j-1]。


 

二 將n劃分爲k個整數的劃分數

dp[i][j]爲將i劃分爲j個整數的劃分數。

  (1) i<j爲不可能出現的情況,dp[i][j]=0

  (2) 若i=j,有一種情況:i可以劃分爲i1之和,dp[i][j]=1

  (3) 若i>j,可以根據劃分數中是否含有1分爲兩類:

                               若劃分數中含有1,可以使用“截邊法”將j個劃分分別截去一個1

                                               把問題轉化爲i-jj-1個劃分數,爲dp[i-j][j-1]; 

                               若劃分中不包含1,使用“截邊法”將j個劃分數的最下面一個數截去,

                                               將爲題轉化爲求i-jj個劃分數,爲dp[i-j][j]。所以i>jdp[i][j]=dp[i-j][j-1]+dp[i-j][j]。



 

三 將n劃分爲若干正奇數之和的劃分數

 

f[i][j]爲將i劃分爲j個奇數之和的劃分數,g[i][j]爲將i劃分爲j個偶數之和的劃分數。

使用截邊法,將g[i][j]j個劃分都去掉1,可以得到f[i-j][j],所以

g[i][j] = f[i-j][j]

f[i][j]中有包含1的劃分方案和不包含1的劃分方案。對於包含1的劃分方案,可以將1的劃分除去,轉化爲“將i-1劃分爲j-1個奇數之和的劃分數”,即f[i-1][j-1];對於不包含1的劃分方案,可以使用截邊法對j個劃分每一個都去掉一個1,轉化爲“將i-j劃分爲j個偶數之和的劃分數”,即g[i-j][j]

所以f[i][j]=f[i-1][j-1]+g[i-j][j]

f[n][0]+f[n][1]+……+f[n][n]爲將n劃分爲若干奇數的劃分數,爲問題4的答案。



另:

將整數劃分成連續正整數之和:


如15可以劃分成4種連續整數相加的形式:
15
7 8
4 5 6
1 2 3 4 5

    首先考慮一般的形式,設n爲被劃分的正整數,x爲劃分後最小的整數,如果n有一種劃分,那麼
結果就是x,如果有兩種劃分,就是x和x 、x + 1, 如果有i種劃分,就是

x ;

x 、x + 1 ;

x、 x + 1、 x + 2 、... ;

x、 x + 1、 x + 2、 ... 、 x + i - 1;
將每一個結果相加得到一個公式(i * x + i * (i - 1) / 2) = n,i爲當前劃分後相加的正整數個數。
滿足條件的劃分就是使x爲正整數的所有情況。
如上例,

當i = 1時,x = 15;

當i = 2時, x = 7;

當i = 3時,x = 4;

當i = 4時,x = 4/9;      (x不是正整數,因此,15不可能劃分成4個正整數相加)

當i = 5時,x = 1;

當i = 6時,x < 1;          (所以i最大爲5)


好了,咱們看題 大笑

03:複雜的整數劃分問題


總時間限制: 200ms 內存限制: 65536kB
描述

將正整數n 表示成一系列正整數之和,n=n1+n2+…+nk, 其中n1>=n2>=…>=nk>=1 k>=1
正整數n 的這種表示稱爲正整數n 的劃分。

輸入
標準的輸入包含若干組測試數據。每組測試數據是一行輸入數據,包括兩個整數N 和 K。
(0 < N <= 50, 0 < K <= N)
輸出
對於每組測試數據,輸出以下三行數據:
第一行: N劃分成K個正整數之和的劃分數目
第二行: N劃分成若干個不同正整數之和的劃分數目
第三行: N劃分成若干個奇正整數之和的劃分數目
樣例輸入
5 2
樣例輸出
2
3
3
提示
第一行: 4+1, 3+2,
第二行: 5,4+1,3+2
第三行: 5,1+1+3, 1+1+1+1+1+1




#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <map>

using namespace std;

int main()
{
    int n, k;
    while( cin >> n >> k )
    {
        int num[n+1][n+1];             // 表示把n分成k個數的dp數組;
        int num1[n+1][n+1];            // 表示把n分成不相等正整數的dp數組;
        int g[55][55], f[55][55];      // g數組爲偶數dp數組, f數組爲奇數dp數組;
        int i, j;
                                    // 初始化;
        for( i=0; i<=n; i++ )
        {
            for( j=0; j<=n; j++ )
            {
                num[i][j] = num1[i][j] = f[i][j] = g[i][j] = 0;
            }
        }
                                    // 這就是上面說的其中兩種。
        for( i=1; i<=n; i++)
        {
            for( j=1; j<=n; j++)
            {
                if( i < j )
                {
                    num[i][j] = 0;
                    num1[i][j] = num1[i][j-1];
                }
                if( i == j )
                {
                    num[i][j] = 1;
                    num1[i][j] = 1 + num1[i][j-1];
                }
                if( i > j )
                {
                    num[i][j] = num[i-1][j-1] + num[i-j][j];
                    num1[i][j] = num1[i-j][j-1] + num1[i][j-1];
                }
            }
        }
                                 //  這裏是最暈的,只要記住就好了,搞懂也沒多大意義;
        f[0][0]=1; g[0][0]=1;
        for( i=1; i<=n; i++ )
        {
            for( j=1; j<=i; j++)
            {
                g[i][j] = f[i-j][j];
                f[i][j] = f[i-1][j-1] + g[i-j][j];

            }
        }

        cout << num[n][k] <<endl;
        cout << num1[n][n] <<endl;
        int sum = 0;
        for( i=0; i<=n; i++)
            sum += f[n][i];
        cout << sum <<endl;
    }
    return 0;
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章