您的位置:首页 > 其它

Game

2016-03-16 19:37 316 查看

题目描述

两个人玩一个游戏。有一个1*n的棋盘,有一些格子已经染了色。两个人轮流操作,每次一个人可以选择一个没有染色的格子,把它染成白色或黑色,要求相邻的格子不能染成相同的颜色。最后不能操作的那个人为输。

给出棋盘的初始状况,并且假设两个人都采取最优策略,问谁会赢?

SG分析

我们设:

sg[0,n]表示现在有连续n个未涂色格子,其两端的格子是不同颜色的估价函数值。

sg[1,n]表示现在有连续n个未涂色格子,其两端的格子是相同颜色的估价函数值。

sg[2,n]表示现在有连续n个未涂色格子,其有一端是格子另一端是边界。

sg[3,n]表示现在有连续n个未涂色格子,其两端的格子都是边界。

举个例子

10002

那么这归属状态sg[0,3]

10001

那么这归属状态sg[1,3]

0001

那么这归属状态sg[2,3]

000

那么这归属状态sg[3,3]

现在我们来推一推它们的转移,懒得写了详见代码

然后打个表,我们可以发现结论

#include<cstdio>
#include<iostream>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=1000+10;
int sg[4][maxn];//0 diff 1 same 2 free1 3 free2
bool bz[maxn];
int i,j,k,l,t,n,m;
int main(){
n=1000;
sg[0][1]=0;
sg[1][1]=1;
sg[2][1]=1;
sg[3][1]=1;
fo(i,2,n){
bz[sg[1][i-1]]=1;
fo(j,1,i-2){
k=i-j-1;
bz[sg[0][j]^sg[1][k]]=1;
}
fo(j,0,n+1)
if (!bz[j]) break;
sg[0][i]=j;
fill(bz,bz+n+2,0);
bz[sg[0][i-1]]=1;
fo(j,1,(i-1)/2){
k=i-j-1;
bz[sg[0][j]^sg[0][k]]=1;
bz[sg[1][j]^sg[1][k]]=1;
}
fo(j,0,n+1)
if (!bz[j]) break;
sg[1][i]=j;
fill(bz,bz+n+2,0);
bz[sg[2][i-1]]=1;
bz[sg[1][i-1]]=1;
bz[sg[0][i-1]]=1;
fo(j,1,i-2){
k=i-j-1;
bz[sg[0][k]^sg[2][j]]=1;
bz[sg[1][k]^sg[2][j]]=1;
}
fo(j,0,n+1)
if (!bz[j]) break;
sg[2][i]=j;
fill(bz,bz+n+2,0);
bz[sg[2][i-1]]=1;
fo(j,1,i-2){
k=i-j-1;
bz[sg[2][j]^sg[2][k]]=1;
}
fo(j,0,n+1)
if (!bz[j]) break;
sg[3][i]=j;
fill(bz,bz+n+2,0);
}
//fo(i,1,20) printf("sg[0][%d]:%d\n",i,sg[0][i]);
//fo(i,1,20) printf("sg[1][%d]:%d\n",i,sg[1][i]);
//fo(i,1,20) printf("sg[2][%d]:%d\n",i,sg[2][i]);
//fo(i,1,20) printf("sg[3][%d]:%d\n",i,sg[3][i]);
}


结论

sg[0,i]=0

sg[1,i]=1

sg[2,i]=i

sg[3,i]=i%2

这是通过打表发现的,而事实证明很多博弈论SG函数的题目的结论都是推理总结打表找规律,可以节约时间,所以这里不予证明(其实证明并不难)。

接下来我们有了sg函数,就可以求了。

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
int i,j,k,l,t,n,m,ca;
bool czy;
char s[100000+10],ch;
int main(){
freopen("game.in","r",stdin);
while (scanf("%d",&n)!=EOF){
do{
s[1]=getchar();
}while (s[1]<'0'||s[1]>'2');
fo(i,2,n) scanf("%c",&s[i]);
czy=0;
fo(i,1,n){
if (s[i]!='0'){
czy=1;
break;
}
}
if (!czy){
if (n%2) printf("FIRST\n");else printf("SECOND\n");
}
else{
fo(i,1,n)
if (s[i]!='0') break;
j=i;
fd(i,n,1)
if (s[i]!='0') break;
k=i;
t=(j-1)^(n-k);
fo(i,j+1,k){
if (s[i]!='0'){
if (i-j>1&&s[j]==s[i]) t^=1;
j=i;
}
}
if (t) printf("FIRST\n");else printf("SECOND\n");
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: