题意: 给出一个连续的棋盘,有的位置为'.',有的位置为'X',二者轮流下子,当有一方获得连续三个子的时候取胜。
对于胜态,一种情况是当前局面出现"XX"/"X.X", 这样直接下一个子就获胜了。
会发现,对于".......X......."这种情况,先手绝对不能在这个X的相邻两格子里落子,否则就会形成上述的胜态给对手。
在排除了这种情况之后,我们可以把棋盘先预处理掉"禁区"部分之后再分解为一块块连续的子棋盘,这些 子棋盘相当于一个个的子问题。另一种胜态的情况就是在某一个'.'处落子之后剩余棋盘的sg值,sg[S']==0而且没有呈现出胜态1的局面,那就说明对手必败。
初始化sg[0]=0,sg[1]=sg[2]=sg[3]=1; 显然1、2、3时候无论落子到哪,剩下的位置都不能再放子了,也就是必败态(零态).
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,sg[220]; 4 char s[220]; 5 bool v[220],idx[220]; 6 bool ok(){ 7 for(int i=0;i<=n-3;++i) 8 if(s[i]=='X'&&s[i+1]=='X'&&s[i+2]=='X') return 1; 9 return 0; 10 } 11 bool _ok(){ 12 for(int i=0;i<n;++i){ 13 if(s[i]=='.'){ 14 s[i]='X'; 15 if(ok()) { 16 s[i]='.'; 17 return 0; 18 } 19 s[i]='.'; 20 } 21 } 22 int ans=0,tmp=0; 23 for(int i=0;i<n;++i){ 24 if(s[i]=='X'|| 25 (i-1>=0&&s[i-1]=='X')|| 26 (i-2>=0&&s[i-2]=='X')|| 27 (i+1<n&&s[i+1]=='X')|| 28 (i+2<n&&s[i+2]=='X')){ 29 ans^=sg[tmp]; 30 tmp=0; 31 } 32 else 33 tmp++; 34 } 35 //cout<<"tmp="<<tmp<<endl; 36 ans^=sg[tmp]; 37 return ans==0; 38 } 39 int main(){ 40 int i,j,k,t,m; 41 sg[1]=sg[2]=sg[3]=1; 42 for(i=4;i<=200;++i){ 43 memset(v,0,sizeof(v)); 44 for(j=1;j<=i;++j){ 45 v[sg[max(0,j-3)]^sg[max(0,i-j-2)]]=1; 46 } 47 for(j=0;;j++){ 48 if(!v[j]){ 49 sg[i]=j; 50 break; 51 } 52 } 53 } 54 cin>>t; 55 while(t--){ 56 cin>>s; 57 n=strlen(s); 58 memset(idx,0,sizeof(idx)); 59 for(i=0;i<n;++i){ 60 if(s[i]=='.'){ 61 s[i]='X'; 62 if(ok() || _ok()) idx[i]=1; 63 s[i]='.'; 64 } 65 } 66 bool can=0; 67 for(i=0;i<n;++i) if(idx[i]) can=1; 68 if(!can) puts("LOSING "); 69 else{ 70 puts("WINNING"); 71 for(i=0;i<n;++i) 72 if(idx[i]){ 73 cout<<i+1; 74 break; 75 } 76 for(i++;i<n;++i) 77 if(idx[i]){ 78 cout<<" "<<i+1; 79 } 80 cout<<endl; 81 } 82 } 83 return 0; 84 } 85 /* 86 5 87 .X....XX.. .... ..XX.. ..... ..X.X.. ... ..XX.. ................ ..XX.. ... ..X.. ..... ..X 88 */ 89 /* 90 4 91 ..... 92 X.....X..X.............X....X..X 93 .X.X...X 94 ............................................... 95 */