bzoj1457: 棋盘游戏

传送门
这题神奇十分神奇,因为这题的胜利条件不是拿走最后一张牌了而是走到(0,0)。
然后就需要大概的转化一下了。
观察到SG函数中如果没有石子了,说明不能移动了,此时SG=0。
首先我们将所有能一步走到(0,0)的位置A集合特殊考虑,这些位置显然是先手必胜的,那么有一些位置B是只能走到这些先手必胜的位置上的,我们就可以把它们的SG函数定为0了。
然后现在的问题成了一个棋盘,走到B集合就不能再移动了,不能移动者输。
于是就是一个很经典的NIM游戏了

#include
#include
#include
#include
#define N 1010
#define M 110
using namespace std;
int t,n,ssgg[M][M];
struct node{int x,y;}pt[N];
int sg(int x,int y){
    if(x==0||y==0)return 0;
    if(x==y)return ssgg[x][y]=0;
    if(ssgg[x][y]!=-1)return ssgg[x][y];
    bool v[10010];
    memset(v,0,sizeof(v));
    for(int k=1;;k++){
        if(x-k<=0&&y-k<=0)break;
        if(x-k>0&&x-k!=y)v[sg(x-k,y)]=1;
        if(y-k>0&&y-k!=x)v[sg(x,y-k)]=1;
        if(x-k>0&&y-k>0)v[sg(x-k,y-k)]=1;
    }
    for(int i=0;;i++)
        if(!v[i])return ssgg[x][y]=ssgg[y][x]=i;
}
int main()
{
    scanf("%d",&t);
    memset(ssgg,-1,sizeof(ssgg));
    while(t--){ 
        scanf("%d",&n);
        int flag=0;
        for(int i=1;i<=n;i++){
            scanf("%d%d",&pt[i].x,&pt[i].y);
       if(pt[i].x==0||pt[i].y==0||pt[i].x==pt[i].y)flag=1;
        }
        if(flag){
            puts("^o^");
            continue;
        }
        int ans=0;
        for(int i=1;i<=n;i++)
            ans^=sg(pt[i].x,pt[i].y);
        if(ans==0)puts("T_T");
        else puts("^o^");
    }
}

你可能感兴趣的:(辣鸡八中,博弈论)