2017-07-07 37 views
3

我有以下矩陣:通過在python重排列的元件最小化在矩陣列的總和

([2, 5, 5, 10] 
[7, 1, 4, 1] 
[1, 3, 3, 9]) 

如果列相加的結果爲:

[10, 9, 12, 20] 

我的目標是確定最佳可以對不同行中的元素進行排序,以便將列總和中的最大元素最小化。

例如,一種可能性是:

([2, 5, 5, 10] 
[7, 1, 4, 1] 
[1, 9, 3, 3]) 

如果列相加的結果爲:

[10, 15, 12, 14] 

這是比第一個較好的解決。

最簡單的方法是檢查所有可能的排列,但是隨着矩陣的增長,這種方法在Python中變得非常慢。

任何想法以更快的方式做到這一點?

回答

2

首先讓加強你的要求,你可以問

"Can I produce a matrix that minimizes the difference between the max sum and the min sum of each column in my matrix" 

這是一件好事,因爲:

  1. 它會滿足你的原始需求,從而解決這一解決你的問題
  2. 關於該要求是容易在每次迭代中顯示次優性,因此我們可以說服自己,貪婪的方法正在發揮作用。

要實現一個貪婪的解決方案,只需保持您的墊的運行總和,併爲每一行插入當前行中的最低值到最高總和列。這確保了色譜柱儘可能均勻堆積。

這將需要m插入爲每個n行和2mlogm各種每一行的所以應該在O(n*m + n*2*mlogm)所以O(nmlogm)運行。

output_mat = [] 

input_mat = [ 
    [2, 5, 5, 10], 
    [7, 1, 4, 1], 
    [1, 3, 3, 9], 
] 

row_size = len(input_mat[0]) 
running_sum = [0] * row_size 

for row in input_mat: 
    sorted_idx = [ 
     x[0] for x in 
     sorted(enumerate(row), key=lambda x: x[1]) 
    ] 

    sum_sorted_idx = [ 
     x[0] for x in 
     sorted(enumerate(running_sum), key=lambda x: x[1], reverse=True) 
    ] 

    new_val_row = [None] * row_size 
    for col_idx,val_idx in zip(sum_sorted_idx, sorted_idx): 
     new_val_row[col_idx] = row[val_idx] 
     running_sum[col_idx] += row[val_idx] 

    output_mat.append(new_val_row) 

for x in output_mat: 
    print ">> %s" % x 
print(running_sum) 

輸出:

>> [2, 5, 5, 10] 
>> [7, 1, 4, 1] 
>> [3, 9, 3, 1] 
[12, 15, 12, 12] 
+0

這並不總是給出最佳結果。你能想出一個更好的算法嗎? – Suparshva

+0

我很想看到這種情況下失敗,我無法找到一個。 – gbtimmon

+0

答案中的例子。使用qwerty提供的算法可以產生更好的結果。在你的算法中,我們收到了'[12,15,12,12]',但通過qwerty的算法,我們收到了'[13,12,12,14]'作爲最後的列和。 – Suparshva

5

這裏有一個想法:

  1. 選擇2列與最小和最大總和。注意它們的區別,d
  2. 檢查兩欄中的元素。找到與差d的最大絕對值的行「使得d」 < dd」> 0
  3. 交換該行中的元素。
  4. 重複步驟1-3,直到步驟2不再可能。

例子: 鑑於

([2, 5, 5, 10] 
[7, 1, 4, 1] 
[1, 3, 3, 9]) 

我們挑兩列用最小和最大總和。這裏我們有最小和的第1列和最大和的第3列。 對於這些2列,它們的和的差,d,是11

([5, 10] 
[1, 1] 
[3, 9]) 

現在,我們發現最大的區別d '這樣d' < dd」 > 0,即9 - 3 = 6。 我們現在交換該行中的元素。因此,我們有

([2, 5, 5, 10] 
[7, 1, 4, 1] 
[1, 9, 3, 3]) 

這個矩陣已經[10, 15, 12, 14]

重複以上過程一次的列 - 和,那麼你將結束與以下:

([5, 2, 5, 10] 
[7, 1, 4, 1] 
[1, 9, 3, 3]) 

這導致基體具有總和爲[13, 12, 12, 14]。此時,步驟2不再可能。所以我們完成了。

+0

在該算法中,如果有多個全球最小/多全球最大總和列,我們可能會在局部最優的解決方案取決於我們採取什麼樣的決定而告終。 – Suparshva

+0

這並不總是有效。我找到了一個案例。它只是重新安排你提供的同一個例子。 '([2,5,5,10] [7,1,4,1] [3,9,3,1])' – Suparshva

+1

@Suparshva有趣的發現...我會看看我是否可以改進它以覆蓋該邊緣情況 – qwerty