一類老鼠進洞模型

問題描述

給定一個序列,序列上有若干\(mouse\)和若干\(hole\),求一組最優的\(mouse\)\(hole\)的匹配。
定義一隻\(mouse\)跑到一個洞\(hole\)的代價爲兩點之間的距離。算法

問題一:洞有容量、有代價 ;

每個洞不必定要進老鼠,但每個老鼠必定要進一個洞。spa

結論一:匹配不會交叉。(顯然)
結論二:對於一組匹配,老鼠和洞不會同時反悔。(從左往右進行匹配,同時反悔會產生交叉)code

而後就能夠用堆模擬費用流啦。
對老鼠和洞分別維護一個堆,設老鼠堆爲\(Q_1\),洞的堆爲\(Q_2\),表示增廣集合。
方便起見先往\(Q_2\)中放一個代價爲\(inf\)、容量爲\(inf\)的洞。io

  • 當碰到一隻老鼠時(位置爲\(x\)),
    \(Q_2\)中取出一個洞的增廣路,設代價爲\(val\)
    因爲老鼠必須匹配,因此答案加上匹配代價\(w = x + val\)
    這隻老鼠能夠與後面的洞匹配,因此往\(Q_1\)中加入反悔操做\(-w - x\)
  • 當碰到一個洞時(位置爲\(x\),代價爲\(cost\)),
    依次從\(Q_1\)中取出老鼠\(u\),直到\(Q_1\)爲空或者這個洞的容量被用完或者本次匹配不優。
    獲取匹配流量\(fl = min(容量 , u.flow)\)
    那麼本次匹配量就爲\(fl\),答案加上\(fl \times\)本次代價\(w = u.val + x + cost\)
    因爲洞有代價,因此會有兩種反悔。
    • 洞反悔,匹配以後的老鼠,在\(Q_2\)中加入代價爲\(-w + u.val - x\)的洞。
    • 老鼠反悔,匹配後面的洞,在\(Q_1\)中加入代價爲\(-w + val\)的老鼠。
    直接這樣\(Q_1\)的複雜度顯然是假的,老鼠進堆的複雜度沒有保障。
    可是注意到老鼠反悔的代價都是\(-w + val = -x - cost\),都是同樣的因此能夠只扔一次。
    記錄一下這個洞匹配的老鼠個數\(cnt\),這樣每一個洞就只會往老鼠堆中扔一次啦!
    咱們已經知道老鼠和洞不會同時反悔,因此直接把這兩種反悔都扔到對應堆中便可。

代碼實現至關簡單:class

Q2.push((Item){inf , 1000000000}) ; Ans = 0 ;
Item u ; ll t , w , fl , cnt ; 
for(int i = 1; i <= n; i ++) {
    if(!p[i].op) {
        u = Q2.top() ;
        Q2.pop() ;
        w = u.val + p[i].x ; Ans += w ; u.flow -- ;
        if(u.flow > 0) Q2.push(u) ;
        Q1.push((Item){- w - p[i].x , 1}) ; 
    }
    else {
        cnt = 0 ; 
        while(p[i].cap && !Q1.empty()) {
            u = Q1.top() ; 
            w = p[i].x + u.val + p[i].cost ; if(w >= 0) break ;
            Q1.pop() ;
            fl = min(p[i].cap , u.flow) ;
            Ans = Ans + 1ll * w * fl ;
            u.flow -= fl ;
            p[i].cap -= fl ; 
            cnt += fl ;
            if(u.flow > 0) Q1.push(u) ;
            Q2.push((Item){- w + p[i].cost - p[i].x , fl}) ;
        }
        if(p[i].cap > 0) Q2.push((Item){- p[i].x + p[i].cost , p[i].cap}) ;
        if(cnt > 0) Q1.push((Item){- p[i].cost - p[i].x , cnt}) ;
    }
}
cout << Ans << endl ; return 0 ;

問題二:洞有容量、有代價 ; 老鼠有容量、有代價

堆模擬費用流,但複雜度沒有保證。
對老鼠和洞都進行兩種反悔(即老鼠和洞都使用問題二中洞的反悔方式)。
常見轉換有:若一個洞必須進老鼠、或者一隻老鼠必須進洞,那麼就把它的代價賦爲\(-inf\)
部分問題的特殊性質能夠保證複雜度,其餘狀況下做爲一個暴力算法仍是很優秀的。im

相關文章
相關標籤/搜索