zoukankan      html  css  js  c++  java
  • 【poj2068】Nim

    Portal -->poj2068

    Description

    ​   给你(S)个石子,有(2n)个人分成两队,编号为奇数的一队,编号为偶数的一队,(2n)个人按照编号从小到大的顺序拿石子,所有人都拿过了就再从(1)号轮,编号为(i)的人一次可以拿(xin[1,a[i]])颗,拿到最后一颗石子的队伍输,判断当前局面是否先手必胜

    Solution

    ​   emmm今天做了几道sg函数的题然后感觉这玩意很神秘

    ​​   除了转化成"有向图游戏"那样的形式之后用异或和和(mex)(sg)以外,还有的题中(sg)的取值只有(0)(1)两种,可以直接判断是否存在一个后继局面的(sg)值为(0)(也就是先手必败态),如果有就说明当前局面(sg)值为(1)(也就是先手必胜态),因为根据P-position(先败)和N-position(先胜)的定义,可以移动到P-position的局面是N-position,所以直接这么判就好了

    ​​   当然你也还是可以转成 一个有向图游戏,只要后继局面中有(0),那么取一下(mex)就只能是(1)了,一样的

    ​​   这题中比较容易想到的就是用"当前是谁准备取"和"当前还剩多少石子"来表示一个局面,那直接大力记忆化搜索就好了,边界条件就是如果当前没有石子了,那么是先手必胜态

    ​​   最后就是求(nxt)的时候模数记得是(2n)而不是(n)。。。

    ​   (一开始陷入了一个误区。。就是觉得每个人的取石子上限不同,所以不是一个ICG,但其实ICG中只是要求移动集合(在这题里也就是能移哪些石子)不与选手相关,并没有限制具体操作)

    ​  

    ​   代码大概长这个样子

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=9000;
    int f[60][N],a[60];
    int vis[N];
    int n,m,S,mark;
    int nxt(int x){return (x+1)%(2*n)==0?2*n:(x+1)%(2*n);}
    int sg(int x,int stone){
    	if (f[x][stone]!=-1) return f[x][stone];
    	if (stone==0) return f[x][stone]=1;
    	int tmp=nxt(x);
    	for (int i=1;i<=a[x]&&i<=stone;++i){
    		if (!sg(tmp,stone-i))
    			return f[x][stone]=1;
    	}
    	return f[x][stone]=0;
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    #endif
    	while (1){
    		scanf("%d",&n);
    		if (n==0) break;
    		memset(f,-1,sizeof(f));
    		scanf("%d",&S);
    		mark=0;
    		for (int i=1;i<=n*2;++i)scanf("%d",a+i);
    		printf("%d
    ",sg(1,S));
    	}
    }
    
  • 相关阅读:
    最值得你学习的编程语言
    【收藏】程序员的资料库--技术文档、视频教程、电子书
    pig 安装
    MySQL导入.sql文件及常用命令
    win7下使用 EasyBCD 硬盘安装centOS
    Linux系统分区
    Hadoop实战教程视频
    中医药小分子和表观遗传重编程
    OpenSSL
    iOS 判断网络连接状态之重写Reachability
  • 原文地址:https://www.cnblogs.com/yoyoball/p/9427020.html
Copyright © 2011-2022 走看看