Loading

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");
}
posted @ 2020-09-05 17:19  MQFLLY  阅读(190)  评论(0编辑  收藏  举报