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

 

 

 

posted @ 2013-10-12 10:22  _随心所欲_  阅读(376)  评论(0编辑  收藏  举报