题意:一个 n×m 的战场,每行中最多由两个士兵,且只能在同一行种移动。两个玩家,每次每个人可最多选择 k 个自己士兵前进或者撤退(向敌人的方向为前进,向自己的方向为后退),选中的士兵可以移动任意距离,但至少移动 1。当某一方不能移动的时候就为输掉,问这次博弈中谁胜谁负或者平局。
题解:这可以看成一个Moore’s Nim-k。特殊情况特判掉,只需要考虑每一行都有双方的士兵个一个的情况,因为玩家双方都是采取最优策略,假设某一方采取撤退进入必胜态,则另一方可以采取进攻相同的距离到达一开始的状态,所以只用考虑双方都会进攻即可。如此一来,每一堆的数目就是双方士兵之间的距离,由此就成为了一个Moore’s Nim-k了。
Moore's Nim-k游戏(抄自网络)
n 堆石子,每次可以从最多 k 堆中取任意多石子,无法拿石子的人输。
结论为:把每堆石子的石子数用二进制表示,统计每个二进制位上 1 的个数,若每一位上 1 的个数全为 (k+1) 的倍数,则必败,否则必胜。
证明如下:
首先,全0为必败态
对于任何一个二进制位 1 的数目,每次最多改变为 k 。(k+1) 的倍数经过操作后不可能成为 (k+1) 的倍数,同时任意非 (k+1) 的倍数可以经过操作后成为 (k+1) 的倍数,所以所有二进制位 1 的个数之和均为 (k+1) 的倍数时为必败态。
#include <bits/stdc++.h> using namespace std; int n,m,k; char s[105][105]; int num[105]; void solve(){ for(int i=0;i<n;i++){ int posG=-1,posR=-1; for(int j=0;j<m;j++){ if(s[i][j]=='G') posG=j; if(s[i][j]=='R') posR=j; } if(posG==-1||posR==-1) num[i]=0; else num[i]=abs(posG-posR)-1; } for(int i=0;i<=10;i++){ int res=(1<<i); int sum=0; for(int j=0;j<n;j++){ sum+=(num[j]/res)%2; } if(sum%(k+1)){ printf("First "); return; } } printf("Second "); } int main(){ cin>>n>>m>>k; int all1=0,all2=0,flag=0; for(int i=0;i<n;i++){ cin>>s[i]; int num1=0,num2=0; for(int j=0;j<m;j++){ if(s[i][j]=='G') num1++; else if(s[i][j]=='R') num2++; } if(num1==0&&num2!=0&&num2!=m) all2++; if(num1!=0&&num2==0&&num1!=m) all1++; } if((all1==0&&all2!=0)){ printf("Second "); return 0; } else if(all1!=0&&all2==0){ printf("First "); return 0; } else if(all1!=0&&all2!=0){ printf("Draw "); return 0; } solve(); return 0; }