标签:cstring amp integer blog style 不能 rip des 状态
从这开始我们来进入做题环节!作为一个较为抽象的知识点,博弈论一定要结合题目才更显魅力。今天,我主要介绍一些经典的题目,重点是去理解模型的转化,sg函数的推理和证明。话不多说,现在开始!
Time Limit: 1000MS | Memory Limit: 10000K | |
Description
Input
Output
Sample Input
2
3
1 2 3
8
1 5 6 7 9 12 14 17
Sample Output
Bob will win
Georgia will win
大致题意是说给一个很长的棋盘,一些地方有棋子,每个格子只能放1个棋子。每次必须要向左移动1个棋子,但不能移除棋盘,也不能超过它左边的第一个棋子。求先手是否必胜。
题解:
(检查草稿箱突然发现自己有暑假的博客没发出来,尴尬......)
这道题上来硬想肯定什么都想不出来。
我们只能通过由浅入深的推理才能做出这道题。
首先我们考虑必败状态的定义:
对于某两个棋子,如果他们两个靠在了一起,那么它们对应的状态就是一个必败状态。
这一点很显然,如果两个棋子贴在一起,先手只能移动前面的棋子,而后手可以通过紧跟先手来继续使先手拿到必败状态。
那么这样,命题得证,这两个紧贴的石子就是一个必败状态了。
那么我们考虑它是从哪里转移而来的:两个棋子如果没有距离了,那么它肯定是从一开始有距离的游戏状态转移过来的.
那么我们可以得到一些式子:
sg(距离为1)=mex(sg(距离为0))=1,
sg(距离为2)=mex(sg(距离为0),sg(距离为1))=2,
sg(距离为3)=mex(sg(距离为0),sg(距离为1),sg(距离为2))=3.......
到这里,读者应该想到了什么了:这就是一个nim游戏的变种!
因此,我们把2个棋子看做1组,之间的空位数看做一堆石子,最后按照nim游戏计算即可。代码见下:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 const int N=1010; 6 int a[N]; 7 inline bool mt(const int &a,const int &b){return a<b;} 8 int main() 9 { 10 int t,n;scanf("%d",&t); 11 while(t--) 12 { 13 scanf("%d",&n);int ans=0; 14 for(int i=1;i<=n;i++) 15 scanf("%d",&a[i]); 16 sort(a+1,a+n+1,mt); 17 for(int i=1;i<=n;i++) 18 if( ((i&1)&&(n&1)) || (!(i&1)&&!(n&1)) )ans^=a[i]-a[i-1]-1; 19 if(!ans)printf("Bob will win\n"); 20 else printf("Georgia will win\n"); 21 } 22 23 }
标签:cstring amp integer blog style 不能 rip des 状态
原文地址:http://www.cnblogs.com/LadyLex/p/7260629.html