题意:竟然是英文,,,难受,就是给你一个10000*1000的棋盘,告诉你当前棋子离左下角顶点的距离是多少,其中你可以向左走任意步,或者向下走任意步,或者沿着斜对角走任意步,谁到左下角顶点赢。
思路:我直接小范围利用SG函数打了个表,(写了很久很久很久。。。)之后找出规律推出了公式,写过了之后求网上搜题解发现是个威佐夫博弈。。。仔细想了想确实啊 ,威佐夫就是有两堆石子,你可以取一堆石子中的任意个或者两堆石子中取出相同个,,这不就是一个往左和往下,一个斜对角嘛,直接写就过了,。。
上代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 10000+10; //int SG[maxn][maxn]; int vis[maxn]; int dir[3][2] = {-1,0,0,-1,-1,-1}; map<int,int>G; void init() { // memset(SG,0,sizeof(SG)); 小范围打表。。 /* for(int i = 0 ; i < 100 ; i++) { SG[i][0] = 1; SG[0][i] = 1; SG[i][i] = 1; } for(int i = 1 ; i < 100 ; i++) { for(int j = 1 ; j < 100 ; j++) { if(i == j ) continue; memset(vis,0,sizeof(vis)); for(int k = 0 ; k < 3 ; k++) { int dx = i , dy = j; while(dx >=0 && dy >= 0) { dx = dx + dir[k][0]; dy = dy + dir[k][1]; if(dx < 0 || dy <0) break; vis[SG[dx][dy]] = 1; } } for(int k = 0 ; ; k++) { if(!vis[k]) { SG[i][j] = k; break; } } } }*/ // 1 2 / 3 5 / 4 7 / 6 10 / 8 13 / 9 15 / 发现规律其实就是每次差的值是 1 2 3 4 5 6 .... G.clear(); int sub = 1; int s = 1; for(int i = 1 ; i <= maxn ; i++)//根据规律去打表 { if(vis[i] || vis[i+sub]) continue; if(i+sub > maxn) break; G[i] = i + sub; // printf("%d %d \n",i,i+sub); vis[i] = 1 , vis[i+sub] = 1; sub++; } } int main() { int n,m; init(); while(scanf("%d%d",&n,&m)!=EOF) { if(n > m ) swap(n,m); if(G[n] != m) puts("Xiao Ren"); else puts("Lao Wang"); } }
另附威佐夫代码。。
#include <stdio.h> #include <iostream> using namespace std; int main(){ int a, b; while(~scanf("%d%d", &a, &b)){ if(a>b) swap(a,b); long k = b-a; printf("%s\n", a==(int)(1.618033989*k) ? "Lao Wang" : "Xiao Ren"); } return 0; }