正整數分組

2021-07-10 20:56:18 字數 2356 閱讀 7197

將一堆正整數分為2組,要求2組的和相差最小。

例如:1 2 3 4 5,將1 2 4分為1組,3 5分為1組,兩組和相差1,是所有方案中相差最少的。 整數個數n<=100,所有整數的和<=10000 

初看題目,第一想到貪心。怎麼貪?排序,每次把數放到「最有利」的一邊,最有利指的是每次都把數放到使得結果差值盡可能小的那邊。這樣的方法顯然前兩個數只能分到不同的組了,這是不對的。比如,這種貪心會把1和2分開,顯然得不到最優解。 最優解是在一起,3自己在一組。

是不是如果找到乙個數和其他幾個數的和相等,就一定先把這個數和另外那幾個數分開放?因為這樣放差值仍然是0。 不是的,看看,我們不能把和3分開。而是應該一起放到一組才最優。

沒招了。萬能的列舉啊,我們把每個數要麼放第一組,要麼放第二組,所以一共2^n種情況,取一種差值最小的就好了。這種方法固然可以,但是實際複雜度太高了。

繼續列舉的思路,我們為什麼要嘗試那麼多情況呢?因為我們在決定第i個數放到哪組的時候,前面的所有2^i-1種情況可能產生的兩組數可能有不同的差值。對!關鍵因素不在於前面的2^i-1種情況,而在於差值的情況。

那麼,我們用bool f(i,j)表示前i個數分成兩組,差值是j的情況是否可能出現。

考慮一下f(i,j)的含義我們把第i個數放到了某一組,差值變成了j (j >= 0)

第i個數放入哪個組有兩種可能:

(1) 第i個數放入原來和比較大的組,那麼放入第i個數的時候差值變成了j,拉大了差值,所以原來的差值是j - ai  (j >=ai),那麼如果f(i-1, j - ai)是true,則f(i,j)也為true

(2) 第i個數放入原來和比較小的組,那麼放入第i個數的時候又有兩種情況:

(2.1) 原來相差很大了,已經是j + ai了,加入ai縮小了差距,於是意味著如果f(i- 1, j + ai) = true,則f(i,j)是true。

(2.2) 原來相差不大, 加入ai之後,和較小的組變成了和較大的組。那麼原來大的比小的和大ai – j (ai >=j), 於是意味著如果f(i – 1, ai – j)是true,則f(i,j)為true。

(1)和(2.2)可以統一成若 f(i-1, |j - ai|) = true,則f(i,j) = true

總結前面說的

f(i,j) = f(i – 1, |j - ai|) || f(i – 1, j + ai)

這裡我們巧妙地運用絕對值和邏輯或運算。

繼續考慮,初值是什麼? f(0,0) = true。沒有數的時候,差值只能是0,其餘f(0,x > 0) = false。

第二維有多大? 第二維大小可以達到所有數的所以時間複雜度是o(n * sum),空間複雜度也是 o(n * sum),這裡sum是所有數的總和。

最終答案是什麼?

根據定義,最終答案是min

空間優化?  f(i, *)只與f(i – 1, *)有關,所以兩行,達到遞推的目的。

上面的解法看起來不是動態規劃,因為動態規劃的式子看起來應該是個「優化」問題,也就是應該有max或者min的樣子,而不是乙個bool值。

那麼我們有別的方法麼?

考慮最後分組情況,如果所有數的和為sum, 較小和的那組數一定不超過 [sum / 2]。我們的目標是使得和較小組的總和盡可能大。

我們的目標是從這n個數中選出一些數,這些數的總和不超過[sum / 2]且總和盡可能大。

那我們重新定義int f(i,j)表示從前i個數中選出的數,總和不超過j的時候能得到的最大的和。

則如果不選擇ai    f(i-1,j) = f(i,j)

如果選擇ai,則f(i,j) = f(i, j - ai) +ai   j >=  ai

第二維大小是[sum / 2]

初值是f(0, x) = 0  注意含義是總和「不超過」x的時候的最大值。

遞推式是 f

(i,j

)={f

(i−1

,j)(

j)max

(f(i

−1,j

),f(

i,j−

ai)+

ai)(

ai<=

j<=[s

um/2

])那麼最終答案是什麼? 根據定義,應該是f(n, [sum / 2])。

時間複雜度和空間複雜度依然是o(n * [sum / 2]) ,同樣可以優化掉一維的空間複雜度。

綜上所述,兩種方法的時間複雜度都是o(n * sum)級別的,通常sum不是很大,比如說本題sum不超過10000,所以從實際角度上講,這個複雜度比o(2^n)強多了。

再順帶說一下如果要求出一組最優解的具體分配方案,怎麼做?

別忘了,動態規劃問題,求具體方案的慣用方法就是記錄當前f(i,j)是由之前哪個狀態得到的,然後一步一步小心謹慎地回退到起點,就像我們在搜尋問題中記錄之前地節點恢復出路徑一樣。

正整數分組

將一堆正整數分為2組,要求2組的和相差最小。例如 1 2 3 4 5,將1 2 4分為1組,3 5分為1組,兩組和相差1,是所有方案中相差最少的。input 第1行 乙個數n,n為正整數的數量。第2 n 1行,n個正整數。n 100,所有正整數的和 10000 output 輸出這個最小差 samp...

正整數分組

將一堆正整數分為2組,要求2組的和相差最小。例如 1 2 3 4 5,將1 2 4分為1組,3 5分為1組,兩組和相差1,是所有方案中相差最少的。整數個數n 100,所有整數的和 10000 初看題目,第一想到貪心。怎麼貪?排序,每次把數放到 最有利 的一邊,最有利指的是每次都把數放到使得結果差值盡...

正整數分組

一 題目描述 題目描述 將一堆正整數分為2組,要求2組的和相差最小。例如 1 2 3 4 5,將1 2 4分為1組,3 5分為1組,兩組和相差1,是所有方案中相差最少的。輸入第1行 乙個數n,n為正整數的數量。第2 n 1行,n個正整數。n 100,所有正整數的和 10000 輸出輸出這個最小差 樣...