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

 

 

 

转载于:https://www.cnblogs.com/xin-hua/p/3364779.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值