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 }