[AGC028C] Min Cost Cycle
Description
給定一個 \(n\) 條邊的有向完全圖,每個點有兩個點權 \(a,b\) 一條邊 \((u,v)\) 的權值為 \(\min(a_u,b_v)\) 。
求邊權和最小的哈密頓迴路的邊權和。
\(2\leq n\leq 10^5, 1\leq a,b\leq 10^9\) 。
Solution
Phase 1
首先既然是哈密頓路,那麼一定會經過所有的 \(a_i, b_i\) 各一次。那麼透過這一點,我們可以把題目的重心從圖的結構中移開,去更多地關注點的性質。先不考慮合法性,令對最終答案有貢獻的數的集合為 \(T\) ,那麼點的結構無非 \(4\) 種:
-
① \(a_i\in T 且 b_i\in T\)
-
② \(a_i\not\in T 且 b_i\in T\)
-
③ \(a_i\in T 且 b_i\not\in T\)
-
④ \(a_i\not\in T 且 b_i\not\in T\)
(圖中的箭頭表示有向邊,而包含有向邊的點表明該有向邊的 \(\min(a,b)\) 在該點上)
接下來就是考慮如何把所有點拼成一個環。
首先發現②可以全部首尾相接等價地縮成一個②,③也同理。一個很顯然的拼法是在全部點都是②或③的情況下,首尾相接拼成一個環,如果既有②也有③且無①、④,那麼是無法拼成一個點的。考慮有①、④的情況,由於 \(|T| = n\) ,所以①④的數量一定是相等的那麼可以透過在一個④左邊拼上③(如果有③的話),右邊拼上②(如果有②的話),然後在③②間交替插入①④,像這樣:
即是一種拼法。
Phase 2
我們考慮一個貪心的構造,欽定將 \(a,b\) 放在一起排序完後最小的 \(n\) 個值為答案,並檢測其正確性。
稍微總結一下 Phase 1 便不難得到,有且僅有一種情況是無法拼成環的,那就是每個點有各有一個 \(a/b\) 且不全為 \(a\) 或 \(b\) 。
在這之後我們繼續貪心地考慮,即在答案中刪掉第 \(n\) 小的值然後加上第 \(n+1\) 小的值。這次僅有一種極端的情況不合法,即第 \(n,n+1\) 為同一個點的 \(a,b\) 且仍沒有形成全為 \(a\) 或 \(b\) 的情形,並沒有改變前一種情形我們所提到的不合法性質。剩下的兩種貪心變換方式一定是合法的,取答案取最小即可。
Code
點選檢視程式碼
int tax[N], typ[2];
struct BLCK{LL val, id, c;}a[N];
int main() {
int n = read(), cntn = 0, flag = 0;
LL ans = 0;
rep (i, 1, n) a[++cntn] = (BLCK){read(), i, 0}, a[++cntn] = (BLCK){read(), i, 1};
sort(a+1, a+1+cntn, [&](BLCK x, BLCK y){return x.val < y.val;});
rep (i, 1, n) flag |= (++tax[a[i].id] > 1), ans += a[i].val, ++typ[a[i].c];
if (flag || max(typ[0], typ[1]) == n) return printf("%lld\n", ans), 0;
ans += a[n+1].val-a[n].val, --typ[a[n].c], ++typ[a[n+1].c];
if (a[n].id != a[n+1].id || max(typ[0], typ[1]) == n) return printf("%lld\n", ans), 0;
printf("%lld\n", min(ans-a[n+1].val+a[n+2].val, ans-a[n-1].val+a[n].val));
return 0;
}
Summary
分析問題時,可以考慮從圖的性質入手,將問題的本質提煉出來,轉化問題為更易求解的形式。