有一個簡單的博弈問題:
現在有一顆 \(n\) 個點的樹,每次詢問後給出一個點連線的所有子節點。
Alice 和 Bob 在樹上博弈。
Alice 和 Bob 每次可以將點向下移動一格。
如果到了葉子節點,便不再移動,互動庫給出葉子權值。
Alice 希望選的數最大,Bob 反之。
求:到達的數最後是多少?
顯然有 \(\mathcal O(n)\) 做法:
\[f(i,0) = \max_{v\in son_i} f(v,1)
\]
\[f(i,1) = \min_{v\in son_i} f(v,0)
\]
但是我們詢問次數想要儘可能小。
若我們搜尋到了一個點。
我們維護兩個變數 \(\alpha,\beta\)。
\(\alpha\) 表示現在可以至少取到 \(\alpha\)。
\(\beta\) 表示現在走到該子樹內可以取到的最大值。
最後 \(\alpha \ge \beta\) 時直接退出即可,因為顯然不優。
int alpha_beta(int u, int alph, int beta, bool is_max) {
if (!son_num[u]) return val[u];
if (is_max) {
for (int i = 0; i < son_num[u]; ++i) {
int d = son[u][i];
alph = max(alph, alpha_beta(d, alph, beta, is_max ^ 1));
if (alph >= beta) break;
}
return alph;
} else {
for (int i = 0; i < son_num[u]; ++i) {
int d = son[u][i];
beta = min(beta, alpha_beta(d, alph, beta, is_max ^ 1));
if (alph >= beta) break;
}
return beta;
}
}
引用了 oi-wiki 上的程式碼。