hdu 1730 sg博弈||nim博弈
http://acm.hdu.edu.cn/showproblem.php?pid=1730
现在我们看单独的一行,也就是说两个人进行棋子的移动,使得任何一方不能走了便是获胜!那么我们换一个方式看棋局的必败态,也就是当两个棋子的相邻的时候,那么先手是必败的。这个时候我们假设两个人都是热衷于取得胜利,并且是要使的两个棋子间的距离减小的走子方式,于是我们通过sg函数的定义,爆出sg函数值就发现sg函数值就是两个棋子的距离的绝对值减1.其实这个还是可以理解的,因为我们看当两个棋子相邻的时候,已经是一个必败态了。因此我们得到了每一棋局的sg函数值。最后对sg函数值进行异或看结果就能知道整个棋局的状态了。
我们来分析只有一行的情况:
我们知道只要黑白棋子之间有空格,只要谁先走就一定谁赢,因为先走者一定会走到与两个棋子之间没有空格的地方,这样才能保证他赢,我们看成取石子且石子只有一堆的情况;
那么多行时,我们就可以把两个棋子之间的空格看成有多少个石子,而行可以看成有多少堆,再利用Nim就可以解决问题了;
最开始还想通过>=2的奇偶行直接进行判断,wa了。和华哥讨论了下,发现有问题。需要考虑必胜和必败两种情况。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// I'm lanjiangzhou //C #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <math.h> #include <time.h> //C++ #include <iostream> #include <algorithm> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <cctype> #include <stack> #include <string> #include <list> #include <queue> #include <map> #include <vector> #include <deque> #include <set> using namespace std; //*************************OUTPUT************************* #ifdef WIN32 #define INT64 "%I64d" #define UINT64 "%I64u" #else #define INT64 "%lld" #define UINT64 "%llu" #endif //**************************CONSTANT*********************** #define INF 0x3f3f3f3f // aply for the memory of the stack //#pragma comment (linker, "/STACK:1024000000,1024000000") //end /*int main(){ int n,m; while(scanf("%d%d",&n,&m)!=EOF){ int a,b; int sum=0; for(int i=0;i<n;i++){ scanf("%d%d",&a,&b); if(abs(a-b)>=2) sum++; } if(sum) printf("I WIN!\n"); else printf("BAD LUCK!\n"); } return 0; }*/ int main(){ int n,m; while(scanf("%d%d",&n,&m)!=EOF){ int t=0; int a,b; for(int i=0;i<n;i++){ scanf("%d%d",&a,&b); t^=abs(a-b)-1; } if(t==0) printf("BAD LUCK!\n"); else printf("I WIN!\n"); } return 0; }