題目描述
使用遞迴編寫乙個程式,求乙個正整數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...