假设围棋棋盘是完全图Kn,那么最优解是什么?
猜想:
以下默认贴子=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;
}

浙公网安备 33010602011771号