uva 1378 - A Funny Stone Game sg博弈

题意:David 玩一个石子游戏。游戏中,有n堆石子,被编号为0..n-1。两名玩家轮流取石子。 每一轮游戏,每名玩家选取3堆石子i,j,k(i<j,j<=k,且至少有一枚石子在第i堆石子中), 从i中取出一枚石子,并向j,k中各放入一枚石子(如果j=k则向k中放入2颗石子)。最 先不能取石子的人输。 石子堆的个数不会超过23,每一堆石子不超过1000个。

解法:看上去是将石子都往右移,直到所有都到了n-1堆不能移为止。首先是考虑每堆石子其实是独立的一个子游戏,堆与堆之间不相互影响。然后就是个数是偶数的对不会影响必胜必败态,必败态无法通过移动偶数堆得石子来扭转局面,因为必胜者只需对称操作即可。所以每堆石子就成了01的状态,sg值只是跟位置有关系了。预处理出每个位置的sg值即可。计算第一个可行步骤时候,暴力判断ijk即可。

代码:

/******************************************************
* @author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
//freopen ("in.txt" , "r" , stdin);
using namespace std;

#define eps 1e-8
#define zero(_) (_<=eps)
const double pi=acos(-1.0);
typedef long long LL;
const int Max=100010;
const LL INF=0x3FFFFFFF;
int sg[100];
bool rem[100];
int n;
void init()
{
    sg[0]=0;
    for(int i=1; i<=25; i++)
    {
        memset(rem,0,sizeof rem);
        for(int j=i-1; j>=0; j--)
            for(int k=j; k>=0; k--)
            {
                rem[sg[j]^sg[k]]=1;
            }
        int t=0;
        while(rem[t]) t++;
        sg[i]=t;
    }
}
bool help[100];
//0 1 2 4 7 8 11 13 14 16 19 21 22 25 26 28 31 32 35 37 38 41 42
int main()
{
    init();
    int kk=1;
    while(cin>>n&&n)
    {
        memset(help,0,sizeof help);
        int ans=0;
        for(int i=0; i<n; i++)
        {
            int a;
            scanf("%d",&a);
            if(a)help[i]=1;
            if(a&1)
            {
                ans^=sg[n-1-i];
            }
        }
        printf("Game %d: ",kk++);
        if(ans)
        {
            for(int i=0; i<n-1; i++)
            {
                if(help[i])
                {
                    for(int j=i+1; j<n; j++)
                        for(int k=j; k<n; k++)
                        {
                            if((ans^sg[n-1-i]^sg[n-1-j]^sg[n-1-k])==0)
                            {
                                printf("%d %d %d\n",i,j,k);
                                goto end;
                            }
                        }
                }
            }
end:
            ;
        }
        else
            puts("-1 -1 -1");
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值