假設圍棋棋盤是完全圖Kn,那麼最優解是什麼?
阿新 • • 發佈:2020-12-30
猜想:
以下預設貼子=0;
n=1: 和棋(顯然)
n=2: 開局兩棄後終局,和棋。誰先動手誰死。
n=3: 如果開局黑棋走棋,白棋有保證不敗的策略。根據copycat lemma,黑棋也有保證不敗的策略。因此最優解還是指向和棋。
n=4: 沒想好
n=5以上... 誰愛研究誰研究去(
數學計算:
我發現在的棋盤上,當時不會出現打劫,也就是不會出現(除了禁全同和禁止自己填滿棋盤以外)禁止落子的情況。這樣的話,棋盤的狀態就可以用個狀態來表示(減去的是棋盤被填滿的非法狀態)。為了考慮全同,在每一個搜尋狀態下,我們都需要記錄經過的所有棋盤狀態。這樣的話,我們搜尋狀態的總數有不超過個。emm...
我實現了深度(暴)優先(力)搜尋的程式。加了一些剪枝後,跑出了n=4的結果,竟然是先手獲勝。
最後的n=5很巧啊,平局
附上程式碼:
#include <iostream> #include <algorithm> #include <cstdio> #include <cmath> #include <vector> using namespace std; #define F first #define S second #define MP make_pair typedef long long ll; const int mx = 10000000; int n, stat_n, length = 0; int full_white = 0, full_black = 0; int pow3[20], exist[mx], record[mx]; void init () { pow3[0] = 1; for (int i = 1; i <= n; i ++) pow3[i] = pow3[i - 1] * 3; for (int i = 0; i < n; i ++) { full_black += pow3[i]; full_white += pow3[i] * 2; } } int encode (int *stat_c) { int msk = 0; for (int i = n; i >= 1; i --) (msk *= 3) += stat_c[i]; return msk; } void decode (int msk, int *stat_c) { for (int i = 1; i <= n; i ++, msk /= 3) stat_c[i] = msk % 3; } int check_result (int msk) { int stat_c[20]; decode (msk, stat_c); int w = 0, b = 0; for (int i = 1; i <= n; i ++, msk /= 3) { b += (msk % 3 == 1); w += (msk % 3 == 2); } return (w == b ? 0 : (w < b ? 1 : -1)); } string Print (int msk) { string s; for (int i = 1; i <= n; i ++, msk /= 3) s += (char)('0' + msk % 3); return s; } void eliminate (int &msk, int side) { int stat_c[20]; decode (msk, stat_c); int emp = 0; for (int i = 1; i <= n; i ++) emp += (stat_c[i] == 0); if (!emp) for (int i = 1; i <= n; i ++) if (stat_c[i] != side + 1) stat_c[i] = 0; msk = encode(stat_c); } typedef pair <int, vector <int> > int_v_int; vector <int> Emp; int_v_int dfs (int msk, int side) { //side: 0->black, 1->white int stat_c[20]; int_v_int res = MP(-1, Emp); //return : -1: lost, 1: win, 0: draw length += (exist[msk] == 0); if (exist[msk] == 2) { int pans = check_result(msk); pans = (side == 0 ? pans : -pans); res.F = pans; return res; } exist[msk] ++; decode (msk, stat_c); //skip int_v_int pres = dfs(msk, side ^ 1); pres.F *= -1; if (pres.F >= res.F) res = pres; if (res.F == 1 || (res.F == 0 && side)) { exist[msk] --; length -= (exist[msk] == 0); res.S.push_back(msk); return res; } //play for (int i = 1; i <= n; i ++) if (stat_c[i] == 0) { int msk_n = msk + pow3[i - 1] * (side + 1); if (msk_n == full_white || msk_n == full_black) continue ; eliminate (msk_n, side); if (exist[msk_n]) continue ; int_v_int pres = dfs (msk_n, side ^ 1); pres.F *= -1; if (pres.F >= res.F) res = pres; if (res.F == 1 || (res.F == 0 && side)) { exist[msk] --; length -= (exist[msk] == 0); res.S.push_back(msk); return res; } } exist[msk] --; length -= (exist[msk] == 0); res.S.push_back(msk); return res; } int main() { cin >> n; init(); int_v_int res = dfs (0, 0); cerr << "result : " << res.F << endl; for (int side = 0, i = res.S.size() - 1; i >= 0; i --, side ^= 1) cerr << Print(res.S[i]) << " " << side << endl; return 0; }