E - Weighted Tic-Tac-Toe (atcoder.jp)
這可不是博弈論!
推了半天性質,腦子要幹爆了,發現這題固定的 \(3\times 3\) 棋盤,可以爆搜啊。
直接用搜尋模擬所有過程即可,難點在優雅地實現。
int a[9];
int dp[512][512];//記憶化
inline bool check(int X) {
for (int i = 0; i <= 6; i += 3) {
if ((X & (1 << i)) and (X & (1 << i + 1)) and (X & (1 << i + 2))) {//橫排三連
return true;
}
}
for (int i = 0; i < 3; ++i) {
if ((X & 1 << i) and (X & (1 << i + 3)) and (X & (1 << i + 6))) {//豎排三連
return true;
}
}
if ((X & 1) and (X & 16) and (X & 256)) {//斜三連
return true;
}
if ((X & 4) and (X & 16) and (X & 64)) {
return true;
}
return false;
}
bool dfs(int S, int T) {//S表示先手下過狀態,T表示後手,用二進位制位儲存,定義先手贏為true
if (check(S)) {//說明先手贏了
return true;
}
if (check(T)) {
return false;
}
if (__builtin_popcount(S) + __builtin_popcount(T) == 9) {//已經走完所有格仍未決出勝負,計算誰分數高
i64 tot{};//分數
for (int i = 0; i < 9; i++) {//統計當前分數
if (S & (1 << i)) {
tot += a[i];
}
else {
tot -= a[i];
}
}
return tot > 0;
}
if (dp[S][T] != -1) {return dp[S][T];}
if (__builtin_popcount(S) == __builtin_popcount(T)) {//目前兩人步數一樣,輪到S先手下
for (int i = 0; i < 9; i++) {
if ((S & (1 << i)) or (T & (1 << i))) {continue ;}//被下過了
if (dfs(S | (1 << i), T)) {//S有情況能贏
return dp[S][T] = 1;
}
}
return dp[S][T] = 0;
}
else {//目前兩人步數不一樣,輪到T後手下
for (int i = 0; i < 9; ++i) {
if ((S & (1 << i)) or (T & (1 << i))) {
continue;
}
if (not dfs(S, T | (1 << i))) {//T有情況能贏
return dp[S][T] = 0;
}
}
return dp[S][T] = 1;
}
}
signed main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
for (auto& x : a) std::cin >> x;
std::memset(dp, -1, sizeof dp);
std::cout << (dfs(0, 0) ? "Takahashi" : "Aoki") << '\n';
return 0;
}