1. 程式人生 > >pku 3159 Candies 第一道Dijkstra+堆維護+差分約束系統的題目

pku 3159 Candies 第一道Dijkstra+堆維護+差分約束系統的題目

本題是一道典型的差分約束系統的題目,題目原意是這樣子的:
    fq是幼稚園班上的老大,一天老師給小朋友們買了一堆的糖果,由fq來分發,在班上,fq和llw是死對頭,兩人勢如水火,不能相容,因此fq希望自己分得的糖果數儘量多餘llw,而對於其他小朋友而言,不患寡而患不均的意識甚是強烈,比如A小朋友強烈希望自己的糖果數不能少於B小朋友m個,即B-A<=m,A,B分別為A、B小朋友的分得的糖果數。如此,班上的小朋友存在若干這樣的意識,題目要求你在滿足其他小朋友的要求的情況下,使fq和llw分得的糖果數差別最大,即max(VN-V1),VN為fq獲得的糖果數,V1為llw獲得的糖果數。
    因此根據題意,可以列出如下的不等式:
    Vb1-Va1 <= a1b1
    Vb2-Va2 <= a1b2    (1)
      .....
    Vbm-Vam <= ambm               
    目標函式為:max(VN-V1)
    題目分析:(1)中的不等式正好可以構成最短路的三角不等式:du <= dv + w(v,w)(其中du、dv分為為u v點到起點的最短路經),因此可以利用最短路經來解求該不等式的解,同時利用最短路經得到的解能滿足max{dn-d1},這一點在上一篇的評論中得到證明(因為圖上的每個點的最短路經都是由其前驅節點(已計算出最短路徑的節點)經過該點和前驅節點的邊鬆弛得到的),因此最短路經得到的解X >= 滿足該不等式的解。由於我們考慮的只是小朋友分得的糖果數的相對量,而不關心其絕對量,因此我們可以假定d1=0,即llw獲得0個糖果數。因此d1==0,而dN達到最大值,固能滿足{dN-d1}達到最大值。
    這道題與poj1716 Integer Intervals、poj1201 Intervals不同 還在於:該題不需要新增虛擬節點V0,因為V1可以從某種程度認為是虛擬節點,即起點。虛擬節點V0在差分約束系統中的作用是作為一個基準量,其他未知數以此基準量並根據不等式條件來得到解,這有點類似於水準高的定義,只是一個相對量。這裡得宣告下:虛擬節點的新增是為保證其他每個頂點均可從V0到達,從而在V0==0的情況下求解其他未知數,即只能以V0為起點,不能使用其他點作為起點,即其他點的未知量不為0。而本題,可以直接令V1=0,即以V1為起點,因為題目考慮的是VN-V1的相對量,因此,直接讓V1=0,讓V1成為起點,便可以。可以說,題目分析到這裡,已經完成了1/3,後面的工作量還是比較大的。
    同時這道題還有一個難度在於資料量比較大,點有30000個,邊有150000條,如果採用bellman_ford演算法,需要的時間開銷為30000*150000=4.5*e9,要在1s的時間算完比較困難。那麼可以用dijkstra麼?當然可以,因為圖中的路徑權都是正的,因此可以用dijkstra,但問題是dijkstra的時間複雜度為o(V*V+E)=9*e8,與bellman_ford演算法其實相差無幾,因此還需要優化。所以在使用dijkstra演算法的同時,利用最小二分堆來實現最小優先佇列的維護,其時間複雜度為o(ElgV)=1.5*lg(30000)*e5~近似等於=1.5*128*sqrt(2)*e5,比9*e8小了小了一個數量級,實踐證明,程式執行時間約等於1s,剛好過,比較險。
    在《演算法導論》中提到,利用斐波那契堆來實現優先佇列,可以將執行時間提升到o(VlgV+E),目前還不知道斐波那契堆,有機會要摸一摸,體現一下告訴最短路經的快感。
    好,本題的題感寫到這裡,這道題做出來比較有成就感啊,雖然有部分思想源於網上,不過還是學到了不少。