加權區間調度問題詳解

題目要求:

    求區間圖的最大加權獨立集。(選擇一部分互不重疊的區間,使得被選出來的區間權重之和最大)


                                               

                                                                                                          圖一

題目分析:

這類問題可以歸結爲區間調度問題,這是其中最普通的一類,即加權最大區間調度問題,其求解思路可以通過求最多區間調度(貪婪算法dp[i-1] = dp[i]),無權最大區間(權值爲1的動態規劃)依次發展過來,其具體思路分析詳見http://blog.csdn.net/yutianzuijin/article/details/45116705#。我也從博客中轉載了這篇文章,http://blog.csdn.net/lukas_sun/article/details/53770959。向原作者致敬!

 

題目求解:

求解最大權值區間的必要條件就是各最優區間互不衝突,這是這類調度問題共同的影子,只不過它的目標是讓各區間的權值和最大。

和所有這種規劃問題相同,我們需要對所有區間進行排序,排序原則爲結束時間的先後,因爲用開始時間排序無法得到各區間明確界限。

首先規定幾個記號

O(j): 需求區間{ 1……j }的最優解集

p ( n ): 最大的滿足不與第n個區間衝突的區間號

OPT( j ): O( j )的最優解值。

由此定義可以分析得到第p(n)+1, p(n)+2 ,p(n)+3…………n-1個區間都與第n個區間衝突,所以O一定包含對需求區間{1,……p(n)}的最優解(否則可以將其替換成最優解而不影響需求區間n),由於p(n) <= n-1,所以如果n不包含在O裏,則其可以轉化爲對需求區間 {1……n-1}的求解。

則我們的遞推模型可以以是否選擇第j個區間爲構造依據。


按照此遞推公式可知求解過程:

OPT(3)= 3 (2,3)

OPT(5)= 5+OPT(0)= 5    (1,5) 

OPT(8)= 6+OPT(4)= 6 +OPT(3)= 9  (2,3)、(4,8)

OPT(10)= 1+OPT(9) = 1+OPT(8)=10 (2,3)、(4,8)、(9,10)

OPT(12)= 10+OPT(6)= 10+OPT(5)>10 =15

OPT(14)= 0+OPT(13)= OPT(12)= 15

OPT(15)= 7+OPT(11)= 7+OPT(10)= 17 >OPT( 14 )

OPT(17)= OPT(15)> = 12+OPT (7) = 17

OPT(18)= 4+OPT(16)= 4+OPT(15)= 21>OPT(17)

綜上,該圖最大權和爲21,在其遞歸算法中的

判斷條件後將所選的邊加入到邊的數組中,調用結束後輸出這個數組可以得到所選邊集:

{(2,3)(4,8)(9,10)(11,15)(16,18)}

若Max()函數和遞歸判斷中的”>”換爲“>=”雖然使最大權值不變但可使所選邊集發生變化,如此例中OPT(17)= 17,但所選邊集爲

     {(1,5)(7,17)}

不同於改動前的邊集:

{(2,3)(4,8)(9,10)(11,15)}

題目擴展:

這個問題可以轉化爲求最大加權獨立集的問題,這種圖論問題廣泛應用於DNA測序等方面,且爲NP問題,求解困難。即將每條線段轉化爲圖中的一個頂點,將有重疊部分的線段設置爲相鄰的頂點,每條線段的權值在頂點數據中體現,則上述問題轉換爲選擇圖中不相鄰的最大權值頂點集。轉換後的圖如圖二所示。

 

圖二

參考文獻

《算法設計》第6章動態規劃 Jon Kleinberg ,Eva Tardos清華大學出版社

《動態規劃》ppt            姜海濤

附錄

求最大權值部分實現代碼

參考姚光超博主的代碼實現

constintMAX_N=100000;

//輸入

intN,S[MAX_N],T[MAX_N];

 

//用於對工作排序的pair數組

pair<int,int>itv[MAX_N];

 

voidsolve()

{

   //pair進行的是字典序比較,爲了讓結束時間早的工作排在前面,把T存入first//S存入second

   for(inti=0;i<N;i++)

   {

            itv[i].first=T[i];

            itv[i].second=S[i];

   }

 

   sort(itv,itv+N);

 

   dp[0]=(itv[0].first-itv[0].second)*V[0];

   for(inti=1;i<N;i++)

   {

            intmax;

 

            //select the ithinterval

            intnonOverlap=lower_bound(itv,itv[i].second)-1;

            if(nonOverlap>=0)

                   max=dp[nonOverlap]+(itv[i].first-itv[i].second)*V[i];

            else

                   max=(itv[i].first-itv[i].second)*V[i];

 

            //do not selectthe ith interval

            dp[i]=max>dp[i-1]?max:dp[i-1];

   }

   printf(%d\n,dp[N-1]);

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章