CodeForces-63E Sweets Game 博弈论,状态压缩,记忆化搜索
CodeForces-63E Sweets Game 博弈论,状态压缩,记忆化搜索
题意
给定一个长度为3的正六边形的棋盘,若为\(O\) 则表示这个位置有糖果。
两人轮流吃糖果,每次可以选择在一条直线上的任意个糖果吃,不能吃的人为败者。
Input
. . .
. . O .
. . O O .
. . . .
. . .
Output
Lillebror
分析
显然是一个博弈问题,但是由于规模非常小,可以考虑直接爆搜。
首先对棋盘的每个位置标号,若位置\(i\) 有\(O\) ,就用一个二进制数的第\(i\) 为\(1\)表示出来。
搜索过程中,如果转移过去的状态不是当前状态的子集,显然是不行的,break就可。
假设转移过去的\(O\) 标号是\(k\) ,那么只需\(tmp ^= 1 << k\) 来转移,表示拿走了这个糖果
注意实现要加括号\((tmp \& (1 << k)) == 0\)
代码
const int dx[] = { 0,1,1 };
const int dy[] = { 2,1,-1 };
int mp[15][15];
int dp[1 << 21];
int solve(int mask) {
if (!mask) return 0;
if (dp[mask] != -1) return dp[mask];
dp[mask] = 1;
for(int x = 0;x < 5;x++)
for (int y = 0; y < 9; y++) {
if (mp[x][y] == -1) continue;
for (int i = 0; i < 3; i++) {
int tmp = mask;
for (int xx = x, yy = y; xx < 5 && xx >= 0 && yy < 9 && yy >= 0; xx += dx[i], yy += dy[i]) {
if (mp[xx][yy] == -1) break;
int k = mp[xx][yy];
if ((tmp & (1 << k)) == 0) break;
tmp ^= 1 << k;
dp[mask] &= solve(tmp);
}
}
}
return dp[mask] ^= 1;
}
int main() {
memset(dp, -1, sizeof dp);
memset(mp, -1, sizeof mp);
int k = 0;
for (int i = 2; i <= 6; i += 2) mp[0][i] = k++;
for (int i = 1; i <= 7; i += 2) mp[1][i] = k++;
for (int i = 0; i <= 8; i += 2) mp[2][i] = k++;
for (int i = 1; i <= 7; i += 2) mp[3][i] = k++;
for (int i = 2; i <= 6; i += 2) mp[4][i] = k++;
int mask = 0;
string s;
for (int i = 0; i < 5; i++) {
getline(cin, s);
for (int j = 0; j < s.length(); j++)
if (s[j] == 'O') mask |= 1 << mp[i][j];
}
if (solve(mask)) puts("Karlsson");
else puts("Lillebror");
}