lightoj 1229 - Treblecross 博弈论

思路:SG函数

枚举先手的每一个位置是否有必胜。

1)如果出现了XXX则必胜;

2)如果出现了XX或X.X则必败;

3)否则计算后手的sg值和。

代码如下:

 

 1 #include<iostream>

 2 #include<cstring>

 3 #include<cstdio>

 4 #include<vector>

 5 #define M 201

 6 using namespace std;  7 char str[M];  8 int sg[M],len;  9 vector<int>p; 10 int get_sg(int m) //计算SG值

11 { 12     if(m<0) return 0; 13     if(sg[m]!=-1) return sg[m]; 14     bool vis[200]={0}; 15     for(int i=1;i<=m;i++) 16         vis[get_sg(i-3)^get_sg(m-i-2)]=1; 17     int i=0; 18     while(vis[i]) i++; 19     return sg[m]=i; 20 } 21 bool cal(int m) 22 { 23     char s[M]; 24  strcpy(s,str); 25     if(s[m]=='X') return 0; 26     s[m]='X'; 27     for(int i=0;i+2<len;i++) //出现XXX

28         if(s[i]=='X'&&s[i+1]=='X'&&s[i+2]=='X') return 1; 29     for(int i=0;i+1<len;i++) //出现XX

30         if(s[i]=='X'&&s[i+1]=='X') return 0; 31     for(int i=0;i+2<len;i++) //出现X.X

32         if(s[i]=='X'&&s[i+2]=='X') return 0; 33     int i,j,ans=0; 34     bool f=0; 35     for(i=0,j=-1;i<len;i++){ //计算后手的SG值和

36         if(s[i]=='X'){ 37             if(f) ans^=get_sg(i-j-5); //当两边都出现的X时要减去4

38             else{ 39                 ans^=get_sg(i-j-3); //当只有一边出现X时要减去2

40                 f=1; 41  } 42             j=i; 43  } 44  } 45     ans^=get_sg(len-j-3); 46     return ans==0; 47 } 48 int main() 49 { 50     int t,ca=0; 51     memset(sg,-1,sizeof(sg)); 52     scanf("%d",&t); 53     while(t--){ 54         scanf("%s",&str); 55         len=strlen(str); 56  p.clear(); 57         for(int i=0;i<len;i++) 58             if(cal(i)) p.push_back(i+1); 59         printf("Case %d:",++ca); 60         if(p.size()){ 61             for(int i=0;i<p.size();i++) 62                 printf(" %d",p[i]); 63             puts(""); 64  } 65         else printf(" 0\n"); 66  } 67     return 0; 68 }
View Code

 

 

 

你可能感兴趣的:(OS)