整數劃分(初級,中級,高階)

2021-10-03 17:15:50 字數 4439 閱讀 5641

題目描述

使用遞迴編寫乙個程式,求乙個正整數n的所有劃分個數。

例如,輸入3,輸出3;輸入4,輸出5。

輸入

多組輸入,每一組是乙個正整數n。

輸出

輸出劃分數。

樣例輸入 copy34

樣例輸出copy35

其實這種問題可以認為是把n劃分為 加數小於或等於某個數的劃分,在這裡把這個數成為m。例如,對6的劃分可以認作是將6劃分為加數小於等於6的劃分,因為6的加數確實小於等於6,為什麼要引入這個m呢,是因為我們發現,從這個角度思考,比較容易求解。我們將劃分的種類數記為q(n,m)

在遞迴裡,要對形參進行判斷

(1)當n=1時 q(1,m):表示是對1的劃分,那麼只有一種劃分方式 1

(2)當m=1時q(n,1):當m=1時其實就是把讓所有加數小於等於1,那就是所有加數都是1咯(不考慮負數),當然也只有一種劃分方式

(3)當n==m時q(n,n):此時就是對n的劃分出來的數沒有限制,預設限制就是不大於n,此時劃分的總類數要分兩種情況才比較好解決:

1.劃分出來的數包含n(或m,因為n==m):那只有一種方式 比如 6的劃分 只有 6;一種方式

2.劃分出來的數不包含n(或m,因為n==m):就可以認為是將6劃分出來的數都小於6,其實就是都小於或等於5,接下來 其實就是求出來q(n,n-1)或者是q(n,m-1),此時n>m-1,放到遞迴方程裡就是求解q(n,m) n>m

綜合起來 q(n,n)=1+q(n,m-1)

(4)當n>m時:當遇到這個問題時,其實可以看做是對n的劃分有了條件,就是所有的劃分出來的數小於m,在上文中,6有11種劃分方式,那是沒有對6劃分出來的數進行限制,當要使劃分出來的數都小於某個數時比如5時,那就不是11種了。

5+1;

4+2,4+1+1;

3+3,3+2+1,3+1+1+1;

2+2+2,2+2+1+1,2+1+1+1+1;

1+1+1+1+1+1;

這個時候分兩種情況:包含m和不包含m :

不包含m就是:

4+2,4+1+1;

3+3,3+2+1,3+1+1+1;

2+2+2,2+2+1+1,2+1+1+1+1;

1+1+1+1+1+1;這些情況,其實就是求6的劃分出來的數小於等於4的情況,放到遞迴方程就是 q(n,m-1)

包含m就是:

5+1;

這個時候,確定這種劃分數量的時候m不再是主角,我們只要求出來n-m的劃分情況就行了,因為此時的m的劃分情況,取決於n-m。 比如包含m=5的劃分情況就是 6-5=1的情況,比如包含4的劃分情況就是求6-4=2,2的沒有限制的劃分情況。放到遞迴方程裡面就是q(n-m,m)

(5)q(n,m)n根據以上分析:

q( n, n ) = 1, 當 n ==1;

q( n, n ) = 1, 當m == 1;

q( n, n ) = q( n,n ) , 當n < m;

q( n, n ) = q( n, m-1) +1 , 當n == m;

q( n, n ) = q( n - m, m ) + q( n , m -1) , 當n > m;

1. 第一種做法(初級)

#include

using

namespace std;

int dp[

5000][

5000];

intmain()

while

(cin >> n)

cout << dp[n]

[n]<< endl;

return0;

}

第二種做法(初級) 遞迴在這裡感謝暉隊(雅神)提供的幫助,下面附上大佬手工講解圖,結構清晰,一幕了然

偷偷附上暉隊的部落格

這是乙個連續四場選拔賽都ak的大佬滴部落格

#include

using

namespace std;

intdfs

(int n,

int all)

return num;

}int

main()

如果資料不大也可以用另一種方法

#include

#include

#include

#include

#include

#include

using

namespace std;

typedef

long

long ll;

int n, ans;

void

dfs(

int i,

int s)

for(i; i <=

10; i++

)//保證每次加的數大於等於原來的

dfs(i, s + i);}

intmain()

}

n劃分成m個整數的和 ,dp[i][j]代表i劃分成j個數(中級

#include

using

namespace std;

int dp[

105]

[108];

intmain()

cin>>t;

while

(t--

)return0;

}

方法二

#include

using

namespace std;

long

long a[

400]

[400];

intmain()

} cout << a[n]

[k]<< endl;

}return0;

}

高階題目:隊花的煩惱描述例:7 3 其中的分法:1 1 5,1 5 1,5 1 1是同一種分法。

輸入

有多組測試資料

每組資料都有兩個整數n,m(6<=n<=500,2<=m<=6)

n表示該整數,m表示把n分成m份

輸出

對每一組測試資料,輸出不同的分法數

樣例輸入

7 310 2

20 3

樣例輸出45

33注意m<=6即可

#include

using

namespace std;

int dp[

505][8

];intmain()

while(~

scanf

("%d%d"

,&n,

&m))

return0;

}

類似的題目將n(n<=50000)分為若干個不同整數的和,有多少種不同的劃分方式,例如:n = 6, ,共4種。由於資料較大,輸出mod 10^9 + 7的結果即可。

開始想的dp[i][j]代表j的最大劃分數不超過i,但是陣列需要開很大。

換個思路就是dp[i][j]代表j劃分成i個整數的方法數,也分有1還是沒有1,跟上面第2題有點類似,但是還要求劃分成不同的整數,所以方程為

dp[i][j]=dp[i][j-1]+dp[i-1][j-i] (有1且僅有1個1)

認真思考會發現i不會超過320,利用等差數列求和求出

#include

using

namespace std;

const

int n =

50000

;const

int mod =

1e9+7;

typedef

long

long ll;

ll dp[

322]

[n+4];

intmain()

while(~

scanf

("%d"

,&n)

)printf

("%d\n"

, ans);}

return0;

}

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

Linux學習經典書籍推薦 初級 中級 高階篇

但是,回歸書籍並不代表說什麼書都看,現在市面上充斥了非常多質量比較一般的書,對我們幫助並不大,甚至可能會起到誤導的作用。而且我們的時間 精力都很有限,所以要看一定就要經典書籍 linux學習經典書籍推薦 初級 中級 高階篇 1 初級篇 熟練使用命令 熟悉shell程式設計 能配置簡單的服務,清楚各類...

初級中級高階測試工程師的區別

初級測試工程師 很多人理解軟體測試就是在計算機按來按去去尋找軟體缺陷,誠然,初級軟體測試工程師一般只做很黑測試,也就是說,按部就班的執行測試用例,當預期結果與實際結果不符時,就認為可能尋找到乙個軟體缺陷,他們往往不關心缺陷後面的邏輯結構。初級測試工程師往往剛畢業缺乏經驗,或者經過短暫的職業培訓初竅門...

glide中級高階

一 glide和circleimageview專案有衝突 直接使用glide切圓形即可 解決 放棄circleimageview,直接使用 glide切圓形。編寫了乙個工具類。複製 即可 將設定為圓形 public static void showimage final context contex...