整數n劃分成k個不為0的部分

2022-05-31 01:48:12 字數 1090 閱讀 1549

題目:洛谷p1025

解法:看到這個題目,我第一反應是組合數學的知識,題目等價於將n個相同的物品(數字1)分成k堆,求方案數。

這道題的解法在高中的排列組合肯定用到過,但是想不起來了。

方法如下:

首先,要保證計算過程中相同的方案(每堆的數量相同,但順序不同)只能計數1次,我採用的是在前一堆的基礎上增加後一堆的數量,保證後一堆的數量不小於前一堆,這樣每堆的數量是遞增的,也就不會擔心相同數量的堆順序不同而重複計數了。

那麼,怎樣保證後一堆的數量不小於前一堆呢?可以直接考慮後一堆的數量=前一堆的數量+i(i>=0),這樣迭代的話需要k-1個迴圈,感覺不太好做,放棄了。

之後,我採用了少量多次,每次分配的堆數不超過上一次的辦法確保後一堆數量不小於前一堆。大體思路是,先分配給k個堆相同的數量i,再分配給h個堆(h=0),令k=h,h更新,繼續進行。一直進行下去,直到可分配的數量變為0或者只剩1堆可以分配,那麼一種分配方案就產生了。

可以看出,這是一種遞迴的演算法。

每一次操作的h、j不同,產生的解決方案也就不同。

而可以發現,當j>1時,分給h個堆的相同數量j可以分成分給h個堆的相同數量1,分j次。取j>1會使我們漏掉一些分配方案。而取j=0相當於什麼都沒乾。

所以我們將,下次分配的數量定為1,當下次分配的數量j確定了,變數也就剩下次分配的堆數h。

分配的堆數h滿足1<=h<=k,要保證下次分配的堆的數量小於當前堆的數量,那麼我們令h=k-下次不打算分配的堆數i(0<=i大體上的思路搞定了,但是題目要求每堆不為空,而如果第一次分配的數目就小於k,那麼是不符合題意的。所以,現將k堆分配數量1,可分配的數量變成n=n-k,堆數k=k,之後再遞迴地進行上述的過程。

**如下:

#include long

long

int sum = 0;//

方案數void div(int n, int k)//

n,k代表可分配的數量和分配的堆數

for (int i = 0; i < k; i++)//

i代表下次不分配的堆個數,對不同的i值進行遞迴

div(n - (k-i), k -i);

}int

main()

找出N個整數中最大的K個數

所謂 第 前 k大數問題 指的是在長度為n n k 的亂序陣列中s找出從大到小順序的第 前 k個數的問題。解法1 我們可以對這個亂序陣列按照從大到小先行排序,然後取出前k大,總的時間複雜度為o n logn k 解法2 利用選擇排序或互動排序,k次選擇後即可得到第k大的數。總的時間複雜度為o n k...

輸入n個整數,輸出其中最小的k個

輸入n個整數,輸出其中最小的k個。詳細描述 介面說明 原型 bool getmink unsignedint uiinputnum,int pinputarray,unsignedint uik,int poutputarray 輸入引數 unsignedint uiinputnum 輸入整數個數 ...

輸入n個整數,求出最小的K個數字

該問題我們可以先維護乙個大小為k的陣列karr,然後遍歷n個整數,當某個值比karr的最大的還要小時,就更新該陣列。如下 include include include include using namespace std void display int intarr,int length co...