ABC349E

加固文明幻景發表於2024-04-14

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;
}