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;
}
时间: 2024-10-13 13:26:39

uva 1378 - A Funny Stone Game sg博弈的相关文章

UVA 1378 - A Funny Stone Game(博弈)

UVA 1378 - A Funny Stone Game 题目链接 题意:给定n堆石头,然后每次能选i, j, k,3堆(i < j <= k),然后从i中哦功能拿一堆出来,往另外两堆放一个进去,最后不能取的输,问先手能否必胜,如果能,输出开始选的3堆 思路:组合游戏,需要转化,把石子一字排开,最后肯定都归到n堆上,n堆是不能取的,所以假设每个石子代表一堆,从左往右分别是n - 1, n - 2, n - 3 ... 2, 1, 0,然后每次取一个加两个,就相当于取掉一堆,多上两堆,这样就转

uva 1378 - A Funny Stone Game(组合游戏)

题目链接:uva 1378 - A Funny Stone Game 题目大意:两个人玩游戏,对于一个序列,轮流操作,每次选中序列中的i,j,k三个位置要求i<j≤k,然后arr[i]减1,相应的arr[j]和arr[k]加1,不能操作的人输,问先手是否必胜,必胜的话给出字典序最下的必胜方案,负责输出-1. 解题思路:首先预处理出各个位置上的SG值,然后对于给定序列,枚举位置转移状态后判断是否为必败态即可. #include <cstdio> #include <cstring&g

UVA - 1378 A Funny Stone Game (SG定理)

Description The funny stone game is coming. There are n piles of stones, numbered with0, 1, 2,..., n - 1. Two persons pick stones in turn. In every turn, each person selects three piles of stones numberedi, j, k (i < j, jk and at least one stone left

Uva 1378 A Funny Stone Game

vjudge上的UVA题面都不好复制... 首先可以发现,每次操作可以从任意堆取一颗石子(除了最后一堆),然后把这颗石子变成两个然后放到这堆后面的任意两堆里去. 而且每次操作最多可以取一个石子. 这样我们就把每个石子看成一个子游戏,位置在i的堆的每个石子看成一个石子数为n-i的堆. 然后再搞一搞sg函数,这题就出来了 #include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm&g

HDU 1848(sg博弈) Fibonacci again and again

Fibonacci again and again Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 6253    Accepted Submission(s): 2603 Problem Description 任何一个大学生对菲波那契数列(Fibonacci numbers)应该都不会陌生,它是这样定义的: F(1)=1; F(2)

uva 1567 - A simple stone game(K倍动态减法游戏)

题目链接:uva 1567 - A simple stone game 题目大意:给定K和N,表示一堆石子有N个,先手第一次可以取1~N-1个石子,取到最后一个石子的人胜利,单词每次操作时,取的石子数不能超过对手上一次取的石子数m的K倍.问先手是否可以必胜,可以输出最小的首次操作. 解题思路:这题想了一天,又是打表找规律,又是推公式的,楞是做不出来,后来在网上找到了一篇题解,将的很清楚,解题宝典 /******************* * K倍动态减法游戏 * 参考:http://www.cn

SG博弈简单题

ZOJ - 2083 - Win the Game 题目传送:Win the Game 最近正在慢慢体会博弈里面的SG函数的意义 此题是最简单的SG博弈问题,只需打个表就OK了 AC代码: #include <map> #include <set> #include <list> #include <cmath> #include <deque> #include <queue> #include <stack> #inc

【UVA1378】A Funny Stone Game (博弈-求SG值-输出方案)

[题目] Description The funny stone game is coming. There are n piles of stones, numbered with 0, 1, 2, ..., n − 1. Twopersons pick stones in turn. In every turn, each person selects three piles of stones numbered i, j, k(i < j, j ≤ k and at least one s

uva 1378博弈

算得上是一个比较复杂的游戏了,解法见论文<解析一类组合游戏>,需要注意的是visit数组要适当开大点防止溢出. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 25; 7 int a[N]; 8 int sg[N]; 9 10 void init() 11 { 12 sg[0] = 0; 13 boo