1. 程式人生 > >動態規劃系列(2)——收益最大問題

動態規劃系列(2)——收益最大問題

考慮一個問題,如果有多個任務,每個任務有自己存在時間段(任務之間的時間段可能有重複),求如果選擇任務可以使收益最大化,計算收益時,每個任務段之間不能有重合。我們舉個實際的例子,存在8個任務,如下圖所示,圖中標明瞭每個任務的時間段和收益。

這個問題我們這樣考慮,從頭到尾,當看到一個任務時,此時不考慮排在後面的任務,考慮在選擇不選擇這個任務時各自的收益,然後選其中的最大值。

第1個任務:選擇時收益為5,不選時則不做任何任務收益為0,。所以面對第一個任務時的最大收益為5;

第2個任務:選擇時收益為1(自身收益+之前最近的一次任務的收益,選擇1時,之前的任務時間重合,收益為0),不選擇時,則是上一個任務的最大收益;

。。。。

我們可以寫一個優化過程的公式,其中OPT代表optimizer(最佳方案),分成選擇和不選擇當前任務兩種情況,如果選擇的話,當前任務的收益和之前可以最近一次時間不衝突的任務的收益;不選擇的話,上一次任務情況下的收益。

根據上面過程可以計算得出下面的結果

按照上面的思路編寫程式碼,首先根據題目求出不選擇本次任務時,上一次的任務標號 。

# -*- coding: utf-8 -*-
'''
假設有8個任務需要完成,每個任務有各自的時間段,8個任務間任務段可能存在重合,如何選擇任務使最後是收益最大
下面為8個任務的時間段
0   1   2   3   4   5   6   7   8   9   10   11
    ******5******
            ****1****
************8************
                *******4*****
            ***********6*********
                    ********3*******
                        ********2********
                                *********4****
*所覆蓋的範圍代表所經歷的時間段,其中的數字代表這個任務可以帶來的收益
'''

def maxIncome():
    tast_incomes = [5,1,8,4,6,3,2,4] # 每項任務的收入
    # 根據時間段的重合情況計算,如果選擇當前任務的話,前面的離得最近的可以做的任務
    prev = [-1,-1,-1,0,-1,1,2,4]  # -1代表如果選擇當前任務的話,之前沒有可選的任務
    # 在面臨每項任務時,選擇或者不選擇的最大收益
    result = [tast_incomes[0]]
    for i in range(1,8):
        if prev[i] == -1:
            result.append(max(tast_incomes[i]+0,result[i-1]))
        else:
            result.append(max(tast_incomes[i]+result[prev[i]],result[i-1]))
            
    return max(result)

if __name__ == '__main__':
    print(maxIncome())