『做題記錄』[AGC028C] Min Cost Cycle

Black_Crow發表於2024-05-30

[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

  分析問題時,可以考慮從圖的性質入手,將問題的本質提煉出來,轉化問題為更易求解的形式。