2016多校6 hdu5795 博弈 sg函数

来源:互联网 发布:微派网络 融资 编辑:程序博客网 时间:2024/06/05 15:08


A Simple Nim

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 677    Accepted Submission(s): 434


Problem Description
Two players take turns picking candies from n heaps,the player who picks the last one will win the game.On each turn they can pick any number of candies which come from the same heap(picking no candy is not allowed).To make the game more interesting,players can separate one heap into three smaller heaps(no empty heaps)instead of the picking operation.Please find out which player will win the game if each of them never make mistakes.
 

Input
Intput contains multiple test cases. The first line is an integer 1T100, the number of test cases. Each case begins with an integer n, indicating the number of the heaps, the next line contains N integers s[0],s[1],....,s[n1], representing heaps with s[0],s[1],...,s[n1] objects respectively.(1n106,1s[i]109)
 

Output
For each test case,output a line whick contains either"First player wins."or"Second player wins".
 

Sample Input
224 431 2 4
 

Sample Output
Second player wins.First player wins.
 

Author
UESTC
 

Source
2016 Multi-University Training Contest 6


藉由此题来学习sg(Sprague-Grundy)函数和nim游戏。

题意:有若干堆石子,两人凭借自己火热的取胜心(的意思就是这两个人在比试中不回失误)从堆中取石子,遵循以下游戏规则:

1、每次可一丛一堆石子中取任意数量的石子,但每次只能对一堆进行操作

2、也可以选择不取,将一堆石子分成三堆,三堆石子的数量自己决定

3、取走最后石子的人胜

这个游戏叫做nim游戏,似乎是博弈论中很经典的一个游戏。若想做出这道题,首先要了解sg函数是什么,下面谈谈我对sg函数的理解:

给定一个有向无环图和一个起始顶点上的一枚棋子,两名选手交替的将这枚棋子沿有向边进行移动,无法移动者判负。sg函数就能描述这个状态

结合本题来讲,当sg函数等于0时,就说明没有下一步操作了,则此时选手状态输。那么怎么计算sg函数的值呢?当只有一堆石子,我们不对它进行分堆操作的时候,它的sg函数就等于它自身的值。
但题目没有那么简单,还能进行分堆操作,对于多堆的石子的sg函数,等于各个堆的sg值作 ^ 运算(这啥玩意),那各个堆的sg函数怎么算呢,。。就是sg(x) =mex{sg(y) : y ∈ F(x)},意思是在非负整数集中将x的所有后继点的sg值全部去掉,然后集合里还剩下的最小非负整数就是x的sg值,比如某数的所有后继点的sg值为{1,2,4},那么这个数的sg值就为0
题目中给的数非常大,直接对每个输入求sg值似乎是不可能的,所以要根据这个游戏的规则打一打每个数sg值表,看看有没有规律可循。那么开撸sg函数吧,最开始我们只知道0、1的sg值,但很快就可以递推出所有的了!

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <cmath>#include <cstdlib>#include <ctime>#include <stack>using namespace std;const int maxn = 105;int sg[maxn];bool vis[maxn];int main(){    int i,j,k;    sg[0]=0;    for(i=1;i<=100;i++){        memset(vis, 0, sizeof(vis));        for(j=0;j<i;j++){            vis[sg[j]]=true;        }        for(j=1;j<i;j++){            for(k=1;k<i-j;k++){                vis[sg[j]^sg[k]^sg[i-k-j]]=true;            }        }        for(j=1;vis[j];j++);        sg[i]=j;    }    for(i=0;i<=100;i++){        cout<<i<<" : "<<sg[i]<<endl;    }    return 0;}
打了个0~100的sg值


根据这个sg值表,我们可以发现8的倍数的数的sg值和他前一位数的sg值是交换的,既然找到规律题目就好做了。将题目输入的多个堆sg的值作 ^ 运算就行了

下面代码:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <cmath>#include <cstdlib>#include <ctime>#include <stack>using namespace std;const int maxn = 1e6;int save[maxn+5];int main(){    int t;    scanf("%d",&t);    while(t--){        int n,i;        scanf("%d",&n);        for(i=1;i<=n;i++){            scanf("%d",&save[i]);            if(save[i]%8==0){                save[i] -= 1;            }else if((save[i]+1)%8==0){                save[i] += 1;            }        }        int judge=save[1];        for(i=2;i<=n;i++){            judge=judge^save[i];        }        if(judge==0){            printf("Second player wins.\n");        }else{            printf("First player wins.\n");        }    }    return 0;}

需要注意的是判断一个数要判断它是不是8的倍数再判断它加一是不是8的倍数,这两个属性只能取其一


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 教育网注册报名的用户名忘了怎么办 艺术生校考通过文化没过本线怎么办 想做主持人 但不是播音专业怎么办 微信登录版本最低登录不上怎么办 所录微课的视频声音小是怎么办 电脑开机黑屏只有光标在闪怎么办 联想家悦重装系统时驱动缺失怎么办 ps做到一半电脑重启了怎么办 宝宝起风疹怎么办 要注意的问题 惠普笔记本刚换的显卡又坏了怎么办 电脑装驱动时不注意点了跳过怎么办 刚抱回来的小猫不吃饭怎么办 三年级小孩字认的太少怎么办 孩子写字手出汗怎么办用什么笔壳 墙壁被小孩用彩色笔画花了怎么办 传图识字里有些字识别不了怎么办 一岁四个月宝宝智力发育迟缓怎么办 小打架受伤对方家长不配合怎么办 宝宝要上幼儿园了家长该怎么办 断奶涨奶怎么办又能防止乳房变形 孩子在幼儿园被小朋友打了怎么办 孩子在幼儿园被小朋友咬了怎么办 孩子被同学打了家长该怎么办? 孩子把同学打了打人家长该怎么办 孩子和同学发生矛盾家长该怎么办 孩子同学给孩子要东西家长该怎么办 如果遇到不讲理的孩子和家长怎么办 孩子调皮又被老师留校了怎么办 孩子拼音f和sh发音不清怎么办 自己在家生的孩子怎么办出生证明 在家念地藏经招来众生不走怎么办 家是济宁孩子上学想在济南上怎么办 高一孩子成绩严重下滑家长怎么办 商铺租客不交租金又不搬走怎么办 考试试卷找不到了明天要交怎么办 8个月宝宝不爱吃蔬菜泥怎么办 5个月的宝宝拉肚怎么办 一岁宝宝大便拉不出来怎么办 八个月宝宝便秘拉不出来怎么办 10个月宝宝大便拉水怎么办 4个月的孩子大便拉水怎么办