平面上有 n 個圓,任意兩圓要么包含、要么分離,不相交不相切。Alice 和 Bob 輪流操作:選一個圓並刪除它及其內部所有圓。無法操作者輸。雙方最優策略下,誰獲勝?
因為圓之間只有「包含」或「分離」,包含關系天然形成一棵或多棵樹(森林):
父圓直接包含子圓,且無其他圓夾在中間。
操作「選一個圓並刪除它及其內部所有圓」等價於在樹上刪除一個節點及其整棵子樹。
經典組合遊戲理論結論(賈志豪《組合遊戲略述》):
(子節點 SG 值 + 1) 的異或和整個森林的 SG 值 = 所有樹根 SG 值異或和。
SG ≠ 0 → 先手必勝;SG = 0 → 後手必勝。
暴力 O(n²) 判斷包含關系會 TLE(n ≤ 20000)。
使用掃描線算法:
x - r(進入),x + r(離開)。struct Circle { int x, y, r; } c[MAXN];
struct Event { int x, type, id; }; // type: +1 進入, -1 離開
// 排序:x 升序,同 x 先進入後離開
// 自定義比較器:比較兩圓在掃描線當前 x 位置的上下關系
struct Comparator {
int sweepX;
bool operator()(int a, int b) const {
// 幾何計算:兩圓在 x=sweepX 時的 y 座標
// 實際需處理圓心在掃描線左側/右側的情況
}
};
set s;
vector tree[MAXN]; // 存儲森林邊
void buildForest() {
// 生成事件、排序
// 掃描處理
// 進入時:it = s.lower_bound(id); 根據 it 和前驅確定父節點
// 離開時:s.erase(id);
}
// 計算 SG 值
int getSG(int u) {
int res = 0;
for (int v : tree[u]) res ^= (getSG(v) + 1);
return res;
}
int main() {
// 讀入、構建森林、計算所有根的 SG 異或和
// 輸出 Alice 或 Bob
}
本題融合了三大知識點:
是「計算幾何 + 遊戲理論 + 數據結構」的綜合性經典題目。