zoukankan      html  css  js  c++  java
  • SG函数 与 ICG问题

    ICG##

    ICG(Impartial Combinatorial Games)游戏是组合游戏(Combinatorial Games)的一类
    满足如下性质:
    ①有两名玩家
    ②两名玩家轮流操作,在一个有限集合内任选一个进行操作,改变游戏当前局面
    ③一个局面的合法操作,只取决于游戏局面本身且固定存在,与玩家次序或者任何其它因素无关
    ④无法操作者,即操作集合为空,输掉游戏,另一方获胜

    Nim游戏##

    Nim游戏是经典的ICG游戏,也是组合游戏的一个重要模型,非常的经典
    对于n堆石子,两名玩家轮流取走其中一堆中的若干石子,不能取走者拜

    结论:我们将石子数异或起来,为0则先手必败,否则先手必胜
    这样的结果也成为Nim和

    SG函数##

    普通的ICG游戏可能就没有Nim游戏来的那么直接,可能会加上若干限制条件,这个时候就需要动用SG函数了

    我们将游戏局面和操作抽象为一个DAG图
    我们定义一个局面x的(SG(x) = mex(SG(y)))
    其中y是x可直达的点,(mex)指取未出现的最小的非负整数
    例如(SG(x) = mex(0,1,3) = 2)

    显然终止状态的SG函数为0

    (SG函数的性质)

    SG为0的状态为必败态
    如果一个局面SG函数非0,说明其一定可以到达SG为0的状态,所以必胜
    如果一个局面的SG函数为0,说明其要么是终止态,可达的局面均非0,必败

    (SG函数解决ICG游戏)

    思考SG函数的定义,如果一个局面(SG(x) = k),意味着其下一步一定会到达一个小于k的局面,而且任意小于k的局面都可达
    像不像取石子?没错

    若ICG游戏分成若干个独立的游戏,我们求出每个游戏的SG函数并求出Nim和,就可以判断局面的胜败

    SG函数的求法:
    如果局面集合不大,可以搜索
    如果局面集合很大,就要通过打表找规律数学推导找到普遍规律,进而加速SG函数的求解

    BZOJ1228为例
    经打表找规律后,可以发现
    SG(a,b) =
    ①a,b为奇,0
    ②a,b为偶,SG(a/2,b/2) + 1
    ③否则设b为奇数,SG(a,b + 1)

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    using namespace std;
    const int maxn = 100005,maxm = 100005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
    	return out * flag;
    }
    int sg(int x,int y){
    	int re = 0;
    	while (true){
    		if ((x & 1) && (y & 1)) return re;
    		else if (!(x & 1) && !(y & 1)) re++,x >>= 1,y >>= 1;
    		else if (x & 1) x++;
    		else y++;
    	}
    	return re;
    }
    int main(){
    	int T = read();
    	while (T--){
    		int n = read(),ans = 0; n >>= 1;
    		for (int i = 1; i <= n; i++)
    			ans ^= sg(read(),read());
    		if (ans) puts("YES");
    		else puts("NO");
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    vue 使用 <iframe> 嵌入网页 地址实现动态配置
    vue 视频播放 vue-video-player
    vue 实现自定义序号, 并且翻页序号累加。
    关于 vue 使用 Handsontable 表格数据导出
    node.js Stream流的使用
    手把手教如何搭建node+egg项目 引入Sequelize
    实现 通过数据库里一个字段值相等 则把 他合为一条数据
    最近在项目中碰到把对象数组转为键值对,
    js 的数组怎么push一个对象. Js数组的操作push,pop,shift,unshift JavaScrip
    for循环
  • 原文地址:https://www.cnblogs.com/Mychael/p/8478448.html
Copyright © 2011-2022 走看看