2014 Super Training #6 A Alice and Bob --SG函数

原题: ZOJ 3666 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3666

博弈问题。

题意:给你1~N个位置,N是最终点,1~N-1中某些格子能够移石头到另外一些指定的格子,1~N-1上有M个石头,位置不定,现在Alice和Bob要把这些石头全部移到N点,谁不能移则输,问先手必胜还是后手必胜。

做法:求出每个位置的SG函数值,然后将放石头的M个位置的SG函数值做异或,异或为0则Alice赢。这里讲坐标反转,1~N换成N-1~0,0点作为终点,更加直观。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define N 10007

int flag[N],step[N];
int sg[N];
vector<int> v[10003];

int mex(int x)
{
    int i,ans = 0;
    memset(flag,0,sizeof(flag));
    for(i=0;i<v[x].size();i++)
        flag[sg[v[x][i]]] = 1;
    for(i=0;;i++)
        if(!flag[i])
            return i;
}

void setSG()
{
    int i;
    sg[0] = 0;
    for(i=1;i<=10002;i++)
        sg[i] = mex(i);
}

int main()
{
    int n,i,j,m,q,c,x,k;
    int cs = 1;
    while(scanf("%d",&n)!=EOF)
    {
        printf("Case %d:
",cs++);
        for(i=0;i<10002;i++)
            v[i].clear();
        for(i=0;i<n-1;i++)
        {
            scanf("%d",&c);
            for(j=0;j<c;j++)
            {
                scanf("%d",&x);
                v[n-i-1].push_back(n-x);
            }
        }
        setSG();
        int res;
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d",&m);
            res = 0;
            while(m--)
            {
                scanf("%d",&k);
                res ^= sg[n-k];
            }
            if(res)
                puts("Alice");
            else
                puts("Bob");
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/whatbeg/p/3822711.html