模擬費用流學習筆記
阿新 • • 發佈:2021-06-21
基本問題
一個數軸上有 \(n\) 只老鼠和 \(m\) 個老鼠洞,第 \(i\) 只老鼠的座標為 \(x_i\),第 \(j\) 個老鼠洞的座標為 \(y_i\)。
尋找一組匹配 \(S=\{(a,b)\mid a\in{\rm mouse},b\in{\rm hole}\}\)。
Problem 1
每隻老鼠只能向左走。
第 \(i\) 只老鼠進第 \(j\) 個洞的代價為 \(x_i-y_j\),求所有老鼠進洞最小代價。
顯然貪心。
考慮 DP
。先把老鼠和洞看成一樣的東西,將其首先按照座標排序,設計狀態 \(f_{i,j}\) 表示從左往右前 \(i\) 個“東西”中,有 \(j\)
如果當前是老鼠:
\[f_{i,j}=f_{i-1,j+1}+x_i \]如果當前是洞:
\[f_{i,j}=\min\{f_{i-1,j-1}-y_i,f_{i-1,j}\} \]由於下標遞增,發現 \(f_{i-1,j-1}-y_i\le f_{i-1,j}\),所以直接選擇前面的決策。
發現每次轉移相當於整體向左/右平移一格、全域性加。這裡我們只需要維護 \(f_{i,0}\) 和差分陣列 \(d_{i,j}=f_{i,j}-f_{i,j-1}\),由於每次相當於在開頭加入/刪除一個元素,使用 棧 即可。複雜度 \(\mathcal O({\rm sort}(n))+\mathcal O(n)\)
int f0 = 0;
stack<int> Q;
for (int i = 1; i <= n; i++)
if (op[i] == 1) // 老鼠
f0 += a[i] + Q.top(), Q.pop();
else // 洞
Q.push(-a[i]);
之後維護的思路與此十分相似。該維護方式之後將具有非常大的優勢。
Problem 2
(to be continue..)