组合博弈博客:https://blog.csdn.net/csdnjiangshan/article/details/79070223
两点结论:
- 如果一个状态的后继状态中,存在一个必败态,则该状态为必胜态;
- 如果一个状态的所有后继状态都为必胜态,则该状态为必败态。
思路:这题中还有平态。同理,结合上面的,如果当前状态的后续状态中没有必败态,且有必平态,那么一定是选必平态。
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<iostream>
#include<map>
using namespace std;
map<int,int>f;
int t,sta,op;
char ch;
int re(int s,int i,int j)//返回第i行第j列的值
{
int _a=(i-1)*3+j;
_a=10-_a;
int y=1;
for(int i=1;i<_a;i++)
y*=10;
s/=y;
return s%10;
}
int up(int s,int i,int j,int x)//把第i行第j列改为x
{
int _a=(i-1)*3+j;
_a=10-_a;
int y=1,cun;
for(int i=1;i<_a;i++)
y*=10;
cun=s%y;
s/=(y*10);
s=s*10;
s+=x;
s=s*y+cun;
return s;
}
int dfs(int x,int s)
{
if(f[s]) return f[s];
int pan=x==1?27:3;
if(re(s,1,1)+re(s,1,2)+re(s,1,3)==pan) return f[s]=2;//判断当前局势
if(re(s,2,1)+re(s,2,2)+re(s,2,3)==pan) return f[s]=2;
if(re(s,3,1)+re(s,3,2)+re(s,3,3)==pan) return f[s]=2;
if(re(s,1,1)+re(s,2,1)+re(s,3,1)==pan) return f[s]=2;
if(re(s,1,2)+re(s,2,2)+re(s,3,2)==pan) return f[s]=2;
if(re(s,1,3)+re(s,2,3)+re(s,3,3)==pan) return f[s]=2;
if(re(s,1,1)+re(s,2,2)+re(s,3,3)==pan) return f[s]=2;
if(re(s,1,3)+re(s,2,2)+re(s,3,1)==pan) return f[s]=2;
int cc[15],cut=0,flag=1;
memset(cc,0,sizeof(cc));
for(int i=1;i<=3;i++)
{
for(int j=1;j<=3;j++)
{
if(re(s,i,j)==0)
{
cc[++cut]=dfs(x==1?9:1,up(s,i,j,x));
}
}
}
if(!cut) return f[s]=3;
for(int i=1;i<=cut;i++)
{
if(cc[i]==2)
{
return f[s]=1;
}
if(cc[i]==3) flag=0;
}
if(flag==1) return f[s]=2;
return f[s]=3;
}
int main()
{
for(scanf("%d",&t); t; t--)
{
f.clear(),sta=0;
for(int i=1; i<=3; i++)
for(int j=1; j<=3; j++)
{
cin>>ch;
sta*=10;
if(ch=='o') sta+=1;//.为0 o为1 x为9
if(ch=='x') sta+=9;
}
cin>>ch;
op=ch=='o'?1:9;
dfs(op,sta);//把图转化为九位数10进制来运算
if(f[sta]==1) printf("%c win!\n",ch);
if(f[sta]==2) printf("%c win!\n",ch=='o'?'x':'o');
if(f[sta]==3) printf("tie!\n");
}
}
/*
2
. . .
. o .
. x .
o
*/