【UVA10561】Treblecross(SG函数)

题意:有n个格子排成一行,其中一些格子里面有字符X。两个游戏者轮流操作,每次可以选一个空格,在里面放上字符X。

如果此时有3个连续的X出现,则该游戏者赢得比赛。初始条件下不会有3个X连续出现。

判断先手胜负情况,若必胜则升序输出先手第一步的所有可选必胜策略

n<=200

思路:如果有XX或者X.X出现则一定先手胜

一个结论:X的旁边和旁边的旁边不能放X

于是整个游戏被不能放X的区域分成了若干个独立的片段,每次都可以选择一个片段进行游戏,就是若干个游戏的和

由于每个棋盘片段都是连续的,想到用一个正整数(即长度)来表示状态,g(x)表示由连续的x个格子组成的棋盘所对应的SG函数值

则有递推方程g(x)=mex(g(x-3),g(x-4),g(x-5),g(1)^g(x-6),g(2)^(x-7)……)

有了g函数,很容易算出初始局面的SG函数,所有使得后继专题SG值为0的决策即为所求

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<cmath>
  6 typedef long long ll;
  7 using namespace std;
  8 #define N   21000
  9 #define oo  10000000
 10 #define MOD 1000000007
 11 
 12 int g[N],flag[N],b[N],c[N],d[N],n;
 13 char a[N];
 14 
 15 int isok(int x)
 16 {
 17     int k=0;
 18     a[x]='X';
 19     for(int i=2;i<=n-1;i++)
 20     {
 21         if(a[i]=='X'&&a[i+1]=='X'&&a[i-1]=='.'){k=i-1; break;}
 22         if(a[i]=='X'&&a[i-1]=='X'&&a[i+1]=='.'){k=i+1; break;}
 23         if(a[i]=='.'&&a[i-1]=='X'&&a[i+1]=='X'){k=i; break;}
 24     }
 25     if(k)
 26     {
 27         a[x]='.'; 
 28         return 0;
 29     }
 30     for(int i=1;i<=n;i++) b[i]=0;
 31     for(int i=1;i<=n;i++)
 32      if(a[i]=='X') 
 33       for(int j=-2;j<=2;j++)
 34        if(i+j>0&&i+j<=n) b[i+j]=1;
 35     int ans=0;
 36     int s=0;
 37     for(int i=1;i<=n;i++)
 38      if(b[i]==0) s++;
 39       else if(s) 
 40       {
 41          ans^=g[s]; 
 42         s=0;
 43       }
 44      if(s) ans^=g[s]; 
 45      a[x]='.';
 46      if(ans) return 0;
 47      return 1;
 48 }
 49 
 50 int main()
 51 { 
 52     //freopen("uva10561.in","r",stdin);
 53     //freopen("uva10561.out","w",stdout); 
 54     g[0]=0;
 55     g[1]=g[2]=g[3]=1;
 56     g[4]=g[5]=2; 
 57     for(int i=6;i<=200;i++)
 58     {
 59         memset(flag,0,sizeof(flag));
 60         for(int j=3;j<=5;j++) flag[g[i-j]]=1;
 61         for(int j=6;j<=i;j++)
 62          if(i-j>=0) flag[g[j-5]^g[i-j]]=1;
 63         int j=0;
 64         while(flag[j]) j++;
 65         g[i]=j; 
 66     }
 67     //for(int i=1;i<=200;i++) printf("%d %d
",i,g[i]);
 68     int cas;
 69     scanf("%d",&cas);
 70     while(cas--)
 71     {
 72         scanf("%s",a+1);
 73         n=strlen(a+1);
 74         for(int i=1;i<=n;i++) d[i]=0;
 75         for(int i=2;i<=n-1;i++)
 76         {
 77              if(a[i]=='X'&&a[i+1]=='X'&&a[i-1]=='.') d[i-1]=1; 
 78              if(a[i]=='X'&&a[i-1]=='X'&&a[i+1]=='.') d[i+1]=1; 
 79              if(a[i]=='.'&&a[i-1]=='X'&&a[i+1]=='X') d[i]=1;
 80         }
 81         for(int i=1;i<=n;i++) b[i]=0;
 82         for(int i=1;i<=n;i++)
 83          if(a[i]=='X') 
 84           for(int j=-2;j<=2;j++)
 85            if(i+j>0&&i+j<=n) b[i+j]=1;
 86         int ans=0;
 87         int s=0;
 88         for(int i=1;i<=n;i++)
 89          if(b[i]==0) s++;
 90           else if(s) 
 91           {
 92               ans^=g[s];
 93               s=0;
 94           }
 95         if(s) ans^=g[s];
 96         s=0;
 97         for(int i=1;i<=n;i++) s+=d[i];
 98         if(ans||s) 
 99         {
100             printf("WINNING
");
101             int m=0;
102             for(int i=1;i<=n;i++)
103              if(a[i]=='.'&&isok(i)) d[i]=1;
104             for(int i=1;i<=n;i++)
105              if(d[i]) c[++m]=i;
106             for(int i=1;i<=m-1;i++) printf("%d ",c[i]);
107             printf("%d
",c[m]);
108         }
109          else 
110          {
111              printf("LOSING
");
112              printf("
");
113          }
114     }
115     return 0;
116 }
117     
原文地址:https://www.cnblogs.com/myx12345/p/9953341.html