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
224 431 2 4
Second player wins.First player wins.
藉由此题来学习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的倍数,这两个属性只能取其一
- 2016多校6 hdu5795 博弈 sg函数
- HDU5795 A Simple Nim(SG函数)
- HDU5795 A Simple Nim sg函数
- HDU5795-A Simple Nim(SG函数)
- hdu5795 博弈
- HDU5795 博弈
- hdu5724 博弈+SG函数+状压 多校1
- SG函数 博弈
- 博弈之sg函数
- 博弈のSG函数
- hoj1848 Sg函数博弈
- 博弈sg函数
- 博弈SG函数
- 博弈sg函数
- 博弈通解:SG函数
- 博弈 SG函数
- sg函数 和 博弈
- 博弈sg函数模板
- linux多线程之自旋锁
- 百度地图SHA1值
- spring,mybatis事务管理配置与@Transactional注解使用
- Uva-10200 Prime Time 【素数+打表+浮点精度】
- 图论专题周赛回顾
- 2016多校6 hdu5795 博弈 sg函数
- java学习日记_2:java之方法 图文解释
- Android View绘制流程与原理
- ensureCapacity()方法提高ArrayList的初始化速度
- 匈牙利命名法
- Java集合框架
- theano学习指南---栈式自编码(源码)
- 机器学习入门读书笔记一(概述)
- 将两个字符转换为一个字节