zoukankan      html  css  js  c++  java
  • SG函数胡乱一气

    (SG)函数乱胡一气

    公平组合游戏转化为有向图游戏

    在一个有向无环图中,只有一个起点,上面有一个棋子,两个玩家轮流沿着有向边推动棋子,不能走的玩家判负。

    定义(mex)函数为不属于集合(S)的最小非负整数

    [mex(S)=min{x}(x otin S,xin N) ]

    (eg:mex({1,2})=0)

    对于状态(x),它有(k)个后继状态(y_1,y_2...y_k),定义(SG)函数

    [SG(x)=mex{SG(y_1),SG(y_2),...SG(y_k) } ]

    SG定理:对于有向图组合游戏,起点为(s_1,s_2...s_n),有定理,当且仅当(SG(s_1)oplus SG(s_2)oplus...oplus SG(s_n) ot=0)时,游戏先手必胜

    (SG)问题初始化时必须指明必败状态

    例题(1:HDU1848~~Fibonacci~again~and~again)

    (3)堆石子,每人任选一堆取走(f)个,(f)必须为斐波那契数,最后取完石子的人胜,先后手谁赢?

    定义(SG[x])表示石子个数为(x)(SG)值,(SG[0]=0),为必败态

    int f[20],n,m,p,sg[N],vis[N];
    int solve(int x){
    	if(~sg[x]) return sg[x];
    	memset(vis,0,sizeof(vis));
    	for(int i = 1;i <= 15;++i){
    		if(x < f[i]) break;
    		vis[solve(x - f[i])] = 1;//转移状态 
    	}
    	for(int i = 0;i <= 2000;++i)
    		if(!vis[i]) sg[x] = i;//mex过程 
    }
    int main(){
    	f[0] = f[1] = 1; f[2] = 2;
    	for(int i = 3;i <= 15;++i) f[i] = f[i-1] + f[i-2];
    	memset(sg,-1,sizeof(sg)); sg[0] = 0;
    	while(~scanf("%d%d%d",&n,&m,&p)){
    		if(n == m == p == 0) return 0;
    		if(solve(n) ^ solve(m) ^ solve(p) == 0) puts("Nacci"); //后手胜 
    		else puts("Fibo"); //先手胜 
    	}
    }
    

    (P2148~~[SDOI2009]E&D)

    有一些游戏,每个游戏都是这样的:

    有两堆石子,每次操作可以丢掉其中一堆,并且把另一堆分至少一个到丢掉的这堆,保证每堆至少有一个石子,不能操作的人输。

    每次可以挑一个游戏操作,最后不能操作的人输。

    根据(SG)定理,求出每一组的(SG)值再全部异或起来

    状态((a,b))可以转移到((c,d){c+d=a)(c+d=b})

    打表吧

    #define bitset<N> B
    B s[M]; int ans[N][N];
    inline int mex(B b){
    	int i = 0; while(b[i]) ++i; return i;}
    int main(){
    	int i,j,k;
    	for(i=2;i<=N;++i)
    		for(j=1,k=i-1;k;++j,--k)
    			s[i].set(ans[j][k]=mex(s[j]|s[k]));//枚举合并
    	for(i=0;i<N;++i)printf("%3d",i);puts("");
    	for(i=1;i<N;++i){//输出矩阵
    		printf("%2d:",i);
    		for(j=1;i+j<=N;++j)
    			printf("%3d",ans[i][j]); puts("");
    	}
    	for(i=1;i<=N;++i){//输出对于每一个a,所有c+d=a的(c,d)的SG值集合
    		printf("%2d:SG%d ",i,mex(s[i]));
    		cout<<s[i]<<endl;
    	}
    }
    

     0:  1  2  3  4  5  6  7  8  9
     1:  0  1  0  2  0  1  0  3  0
     2:  1  1  2  2  1  1  3  3
     3:  0  2  0  2  0  3  0
     4:  2  2  2  2  3  3
     5:  0  1  0  3  0
     6:  1  1  3  3
     7:  0  3  0
     8:  3  3
     9:  0
    

    然后

    int main(){
    	int T = read(),ans,n,x,cnt;
    	while(T--){
    		ans = 0;
    		n = read() >> 1;
    		while(n--){
    			cnt = 0;
    			x = (read() - 1) | (read() - 1);
    			while(x & 1) ++cnt,x >>= 1;
    			ans ^= cnt;
    		}
    		puts(ans ? "YES" : "NO");
    	}
    }
    
  • 相关阅读:
    动态显隐jgGrid的列,改变列名
    从数据库获取bit类型判断的时候要注意大小写
    jqGrid自定义列的用法
    ERP中Ajax的使用
    给DataGrid或Repeater加载树状结构
    jqGrid显示树形结构
    使用json异步获取数据提交表单
    封装jQuery图表插件
    java 多线程 day10 获取线程的返回值 CallableAndFuture
    java 多线程 day09 线程池
  • 原文地址:https://www.cnblogs.com/shikeyu/p/13843096.html
Copyright © 2011-2022 走看看