1. 程式人生 > 其它 >【題解】模擬費用流的一些經典題目

【題解】模擬費用流的一些經典題目

UOJ 455. 雪災與外賣

考慮到球 \(a\),匹配前面的一個洞後應該考慮:

  • 後面有一個球來搶洞:該球失配,非法。
  • 後面有一個洞來搶球:令當前匹配費用為 \(x_a+t\),則相當於讓後面的洞匹配了一個權值為 \(-2x_a-t\) 的球。

考慮到洞 \(b\),匹配前面的一個球后應該考慮:

  • 後面有一個球來搶洞:令當前匹配費用為 \(x_b+w_b+t\),則相當於讓後面的球匹配了一個權值為 \(-2x_b-t\) 的洞。
  • 後面有一個洞來搶球:令當前匹配費用為 \(x_b+w_b+t\),則相當於讓後面的洞匹配了一個權值為 \(-x_b-w_b\) 的球。

注意到因為一個洞會出現很多次,所以可以多次考慮匹配,當匹配不優的時候就把剩下的洞一股腦的丟進堆裡即可。

程式碼:提交記錄 #507879 - Universal Online Judge (uoj.ac)


ICPC World Finals 2018 征服世界

在 lca 統計貢獻,如果堆頂可以使得答案更小那麼更新(注意到因為要求所有球必須進洞,所以最開始給每個球一個極小附加權值保證每個球都會被匹配),同時新增反悔。

注意到因為兩個匹配點不可能同時反悔(不會使得答案變優),所以總共需要處理的球和洞的級別是軍隊總數的,時間複雜度 \(O(S\log S)\)

程式碼:提交記錄 #1254764 - LibreOJ (loj.ac)


NOI2019 序列

依次加入 \(a_i\),考慮增廣路怎麼走:

  • \(S\rightarrow a_i\) 然後 \(a_i\rightarrow b_i\) 最後 \(b_i\rightarrow T\) 。 (走第一類匹配邊)
  • \(S\rightarrow a_i\),然後 \(a_i\) 走附加邊去到某個 \(b\) 後去 \(T\) 。(走第二類匹配邊)
  • \(S\rightarrow a_i\) 然後 \(a_i\rightarrow b_i\),接著沖掉之前和 \(b_i\) 匹配的點,走附加點回到 \(a_j\),對應點 \(a_j\) 走對應的 \(b_j\)\(T\) 。(走第一類匹配邊衝第二類匹配邊變為第一類匹配邊)
  • \(S\rightarrow a_i\)
    然後 \(a_i\rightarrow b_i\),接著沖掉之前和 \(b_i\) 匹配的點,走到附加點尋找新的匹配 \(b_k\) 走到 \(T\) 。(走第一類匹配邊衝第二類匹配邊變為第二類匹配邊)
  • \(S\rightarrow a_i\),然後 \(a_i\) 走附加邊去對面選點,沖掉之前走附加邊的某個 \(a_j\),讓 \(a_j\)\(b_j\)\(T\) 。(走第二類匹配邊衝第二類匹配邊變為第一類匹配便)

一共五種簡單的增廣路(注意到不會有 "走第二類匹配邊衝第二類匹配邊變為第二類匹配邊" 的情況,這種情況和 "走第二類匹配邊" 沒有區別,因為不關心誰匹配了誰)。

注意到正常描述增廣路的方式應該是 "在左右點亂跳,然後最後跳到 \(T\) 表示找到一對新的匹配",看樣子不能簡單歸為上面五種。

但其實對於這樣的增廣路,可以先找到重複點直接 匹配,容易發現這樣子肯定不會變劣,所以最開始就不會出現左右部點重複的情況。接著考慮剩下的東西,注意到模擬費用流時,存下來的反悔方案都不用具體地表示出增廣路:這意味著,我們知道左右部匹配了多少點,但是不用關心具體怎麼匹配的(事實上模擬費用流都是這樣的)。所以我們認為新增節點的時候,只需要討論上述五種簡單的增廣路。

討論一下這五類增廣路碰到的點的狀態:

  • \(a_i\) 未匹配,\(b_i\) 未匹配:\(a_i+b_i\) 最大。
  • \(a_i\) 未匹配,\(b_i\) 不管;\(a_j\) 不管,\(b_j\) 未匹配:\(a_i+b_j\) 最大。
  • \(a_i\) 未匹配,\(b_i\) 已匹配;\(a_j\) 已匹配,\(b_j\) 未匹配:\(a_i+b_j\) 最大。
  • \(a_i\) 未匹配,\(b_i\) 已匹配;\(a_j\) 已匹配,\(b_j\) 不管;\(a_k\) 不管,\(b_k\) 未匹配:\(a_i+b_k\) 最大。
  • \(a_i\) 已匹配,\(b_i\) 未匹配;\(a_j\) 不管,\(b_j\) 已匹配;\(a_k\) 未匹配,\(b_k\) 不管:\(a_k+b_i\) 最大。

可以發現後兩條中間的 \(a_j\) 其實不需要討論,此時只需要維護:

  • \(a_i\) 未匹配,\(b_i\) 未匹配:\(a_i+b_i\) 最大。
  • \(a_i\) 未匹配,\(b_i\) 已匹配:\(a_i\) 最大。
  • \(a_i\) 已匹配,\(b_i\) 未匹配:\(b_i\) 最大。
  • \(a_i\) 未匹配,\(b_i\) 不管:\(a_i\) 最大。
  • \(a_i\) 不管,\(b_i\) 未匹配:\(b_i\) 最大。

將所有的 \(i\) 分為了五類,用五個堆維護,然後模擬五種增廣路帶來的影響即可。

程式碼:提交記錄 #1256954 - LibreOJ (loj.ac)

考慮增廣路好像還要有順序的,如果順序錯了就是過不去?我是真的不懂。