大白书 2.4节 组合游戏(博弈论)

大白书 2.4节 组合游戏
博弈论笔记:
1)必胜必败状态:
a)一个状态为必胜状态,充要条件是后续状态有一个必败状态
b)一个状态为必败状态,充要条件是后续状态全是必胜状态
2)SG函数
a)定义:SG[i] = {所有i的后继SG值中,不在这些值之中的最小非负整数}
b)一个状态为必败状态,当且仅当这个状态的SG值为0
c)通常可以用暴力的方法求出参见第二道题,数据过大时参见第一道题
3)Nim和与SG函数的应用
a)Nim和:一个父游戏的状态等于子游戏状态的异或和。
b)一个游戏的SG值,等于所有子游戏的SG值的异或和
UVA 1146
看的题解
找规律,n为偶数SG值为n/2,奇数为SG[i] = SG[i/2]
源码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
#define LL long long
LL sg(LL u)
{
    if(u % 2 == 0)  return u / 2;
    return sg(u / 2);
}
int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        int n;
        scanf("%d", &n);
        LL state = 0;
        while(n--){
            LL u;
            scanf("%lld", &u);
            state ^= sg(u);
        }
        if(state == 0)   printf("NO\n");
        else    printf("YES\n");
    }
    return 0;
}

UVA 10561
看的题解和别人代码
对于一个X,存在控制区间即[x-2,x+2],在这个区间内放X就输了。
然后根据这个性质得出SG函数以及的特判输赢的情况。
然后枚举每个不在控制区间、不为X的位置变成1后SG是否为0,得出所有位置的解。
源码:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
using namespace std;
const int MAXN = 200 + 5;
int vis[MAXN];
int sg[MAXN];
void init()
{
    sg[0] = 0;
    sg[1] = sg[2] = sg[3] = 1;
    for(int i = 4 ; i < MAXN ; i++){
        memset(vis, 0, sizeof(vis));
        for(int j = 1 ; j <= i ; j++){  ///枚举以那个点为划分点,然后[i-2,i+2]均失效
            int l = max(0, j - 3);
            int r = max(0, i - j - 2);
// if(i == 5){
// printf("l = %d, r = %d\n", l, r);
// }
            vis[sg[l] ^ sg[r]] = 1;
        }
        for(int j = 0 ; ; j++){
            if(vis[j] == 0){
                sg[i] = j;
                break;
            }
        }
    }
}
char op[MAXN];
int ts[MAXN], s[MAXN];
int n;
vector<int>ans;
bool check1()
{
    int ok = 0;
    ans.clear();
    for(int i = 1 ; i <= n ; i++){
        if(i > 2 && ts[i - 2] == 1 && ts[i - 1] == 1) ok = 1, ans.push_back(i);
        if(i <= n - 2 && ts[i + 1] == 1 && ts[i + 2] == 1)   ok = 1, ans.push_back(i);
        if(i < n && i > 1 && ts[i] == 0 && ts[i - 1] == 1 && ts[i + 1] == 1)   ok = 1, ans.push_back(i);
    }
    return ok;
}
int SG()
{
    int state = 0;
    int cnt = 0;
// printf("/***");
// for(int i = 1 ; i <= n ; i++) printf("%d ", s[i]);
// printf("***///\n");
    for(int i = 1 ; i <= n ; i++){
        if(s[i] == 1){
// printf("cnt = %d\n", cnt);
            state ^= sg[cnt];
            cnt = 0;
        }
        else    cnt++;
    }
// printf("cnt = %d\n", cnt);
    state ^= sg[cnt];
// printf("state = %d\n", state);
    return state;
}
int main()
{
// freopen("UVA 10561.in", "r", stdin);
    init();
// printf("sg[5] = %d\n", sg[5]);
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%s", op);
        n = strlen(op);
        for(int i = 0 ; i < n ; i++){
            if(op[i] == 'X')    ts[i + 1] = 1;
            else    ts[i + 1] = 0;
        }
        for(int i = 1 ; i <= n ; i++){
            s[i] = 0;
            for(int j = max(1, i - 2) ; j <= min(n, i + 2) ; j++){
                if(ts[j] == 1){
                    s[i] = 1;
                    break;
                }
            }
        }
        if(check1()){///第一步即胜利
            printf("WINNING\n");
            vector<int>::iterator newend = unique(ans.begin(), ans.end());
            ans.erase(newend, ans.end());
            int f = 1;
            for(vector<int>::iterator it = ans.begin() ; it != ans.end() ; it++){
                if(f)   f = 0;
                else    printf(" ");
                printf("%d", *it);
            }
            printf("\n");
            continue;
        }
        else if(SG() == 0){
            printf("LOSING\n\n");
        }
        else{
// printf("///***");
// for(int i = 1 ; i <= n ; i++) printf("%d ", s[i]);
// printf("***///\n");
            ans.clear();
            for(int i = 1 ; i <= n ; i++){
                if(s[i] == 0){
                    memcpy(ts, s, sizeof(ts));  ///ts用于保存s的初始状态
                    for(int j = max(i - 2, 1) ; j <= min(i + 2, n) ; j++)
                        s[j] = 1;
// printf("i = %d, SG() = %d\n", i, SG());
                    if(SG() == 0)   ans.push_back(i);
                    memcpy(s, ts, sizeof(ts));
                }
            }
            printf("WINNING\n");
            int f = 1;
            for(vector<int>::iterator it = ans.begin() ; it != ans.end() ; it++){
                if(f)   f = 0;
                else    printf(" ");
                printf("%d", *it);
            }
            printf("\n");
        }
    }
    return 0;
}

你可能感兴趣的:(大白书 2.4节 组合游戏(博弈论))