1. 程式人生 > >【SG函式 && 存在不可達狀態】Gym

【SG函式 && 存在不可達狀態】Gym

Step1 Problem:

一個 100*100 的棋盤,棋盤上有 n 個棋子,Alice 和 Bob 輪流進行操作。
操作:選擇棋盤上的一枚棋子 (l,c)(l, c),移動至 (lu,c)(l,cu)(lu,cu)u>=1(l-u, c),(l, c-u),(l-u, c-u), u >= 1, 同時不能出界。
誰先把第一個棋子移動至 (0, 0) 的誰獲勝。
問先手能否獲勝。

Step2 Ideas:

第一點: 沒有人會傻到把棋子移動到第一行,或者第一列,或者 行列 相等的位置。( 除了 (0, 0) )。
所以我們把這些位置設為不可到達的位置。
所以當所有棋子都到達 (1, 2) 或者 (2, 1) 後獲勝。
問題就變成了一個簡單的求 sg 的博弈。

Step3 Code:

#include<bits/stdc++.h>
using namespace std;
int sg[105][105];
void init()
{
    memset(sg, 0, sizeof(sg));
    for(int i = 1; i <= 100; i++)
    {
        for(int j = 1; j <= 100; j++) {
            if(i==j) continue;
            int mex[10005] = {0};
            for(int u = 1; u <= max(i, j); u++) {
                if(u < i && i-u!=j) {
                    mex[sg[i-u][j]]++;
                }
                if(u < j && j-u!=i) {
                    mex[sg[i][j-u]]++;
                }
                if(u < i && u < j) {
                    mex[sg[i-u][j-u]]++;
                }
                while(mex[sg[i][j]]) sg[i][j]++;
            }
        }
    }
}
int main()
{
    init();
    int n;
    scanf("%d", &n);
    int flag = 0, ans = 0;
    int x, y;
    for(int i = 1; i <= n; i++) {
        scanf("%d %d", &x, &y);
        if(x==y) {
            flag = 1;
        }
        else if(x==0 || y==0) flag = 1;
        else ans ^= sg[x][y];
    }
    if(flag) printf("Y\n");
    else {
        if(ans) printf("Y\n");
        else printf("N\n");
    }
    return 0;
}