Codeforces Gym 102392F Game on a Tree (SEERC2019 F題) 題解


題目鏈接https://codeforces.com/gym/102392/problem/F

題意:被這題題意坑了很久,大意是說有一棵根為 \(1\) 的樹,每個節點初始都是白色, \(Alice\) 能在這棵樹的某個節點放下一個棋子,並使得該節點變為黑色,然后從 \(Bob\) 開始,兩人能輪流移動這個棋子到當前所在節點的任意一個白色的祖先或者后代節點(不需要相鄰的節點),並且將移動到的節點染為黑色。誰先不能移動就輸了。

分析:看到這道題,大致就是一個樹上的博弈問題。我們一開始讀錯題意,以為必須得是移動到與當前節點相鄰的節點,那這道題就很容易轉化為求樹上最大匹配的問題。我們發現如果這棵樹的最大匹配是完美匹配,那么后手必勝,反之先手必勝,原因是:不論先手選哪一個節點,后手都能將棋子移動到與當前節點匹配的某一節點。但如果不存在完美匹配,那先手必然能避免這種情況。然后敲了個樹上最大匹配交了上去就wa32了。。。

最后才發現不需要移動到相鄰節點,事實上解決方法也類似上面說的樹上最大匹配,只不過這個最大匹配並不需要相鄰節點,只要某兩個點滿足互為祖先節點和后代節點就能匹配,這個問題可以通過樹形 \(dp\) 解決。

我們記 \(dp_v\)\(v\) 節點以及該節點對應子樹未匹配節點的最小數量, \(cnt\)\(\sum{dp_k}\) (v節點所有后代節點dp值之和),那么就容易得到:$$\begin{cases}
dp_v = cnt - 1 (cnt > 0), \ dp_v = 1 (cnt = 0). \
\end{cases}

\[如果 $dp[1]$ 的值為$0$ ,說明存在完美匹配。 **AC代碼**: ``` #include <bits/stdc++.h> using namespace std; void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); } int n, x, y, dp[SIZE]; bool vis[SIZE]; vector<int> G[SIZE]; void dfs(int fa, int now) { bool f = false; dp[now] = -1; for (auto i : G[now]) { if (i == fa) continue; dfs(now, i); if (vis[i]) f = true; dp[now] += max(dp[i], (vis[i] ? 1 : 0)); } if (!f || dp[now] > 0) vis[now] = true; } int main() { io(); cin >> n; rep(i, 1, (n - 1)) { cin >> x >> y; G[x].emplace_back(y); G[y].emplace_back(x); } dfs(0, 1); if (dp[1]) puts("Alice"); else puts("Bob"); } ```\]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM