【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. Two
persons 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 stone left in pile i). Then, the person gets one stone out of pile i, and
put one stone into pile j and pile k respectively. (Note: if j = k, it will be the same as putting two
stones into pile j). One will fail if he can’t pick stones according to the rule.
David is the player who first picks stones and he hopes to win the game. Can you write a program
to help him?
The number of piles, n, does not exceed 23. The number of stones in each pile does not exceed 1000.
Suppose the opponent player is very smart and he will follow the optimized strategy to pick stones.

Input
Input contains several cases. Each case has two lines. The first line contains a positive integer n
(1 ≤ n ≤ 23) indicating the number of piles of stones. The second line contains n non-negative integers
separated by blanks, S0, . . . , Sn−1 (0 ≤ Si ≤ 1000), indicating the number of stones in pile 0 to pile
n − 1 respectively.
The last case is followed by a line containing a zero.
Output
For each case, output a line in the format ‘Game t: i j k’. t is the case number. i, j and k indicates
which three piles David shall select at the first step if he wants to win. If there are multiple groups of
i, j and k, output the group with the minimized lexicographic order. If there are no strategies to win
the game, i, j and k are equal to ‘-1’.

Sample Input
4
1 0 1 100
3
1 0 5
2
2 1
0
Sample Output
Game 1: 0 2 3
Game 2: 0 1 1
Game 3: -1 -1 -1

【题目翻译】

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

请编程帮助David。

石子堆的个数不会超过23,每一堆石子不超过1000个。

【分析】

  首先,假设第i堆有xi个石子,那么可以先把xi%2。

  因为在同一堆中的两颗石子是一模一样的。对方对这颗石子做什么,你就可以对另外一颗石子做同样的事,相当于这两颗一样的石子不存在。

  因为每颗石子可以变成两颗放到后面去,也就是说它的转移状态和它的编号有关。

  可以将每一颗石子看作是一堆石子,如果它是第p堆中的石子,把么它所代表的这堆石子的个数为n-1-p。

  因为石子堆是互不干扰的,因此这个游戏可以看作由若干个只有一堆石子的游戏组成。(把其单独考虑开来)

  求它能到达的子状态的尼姆和更新自己的sg值即可。跟扫楼梯一题差不多,即使这堆石子的个数为偶数个,他可能还是有用的,即可以拆分也把状态改变为平衡状态的,要把这个也考虑上。(好像说得不是很清楚,具体看代码吧~~)

代码如下:(看错数据范围了,懒得改了,就酱吧~)

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<queue>
 7 using namespace std;
 8 #define Maxn 1010
 9
10 int n;
11 int a[2*Maxn],b[2*Maxn],sg[2*Maxn];
12 bool vis[2*Maxn];
13
14 void get_sg(int x)
15 {
16     memset(vis,0,sizeof(vis));
17     for(int i=1;i<x;i++)
18      for(int j=i;j<x;j++)
19      {
20          vis[sg[i]^sg[j]]=1;
21      }
22     for(int i=0;i<=2000;i++)
23         if(vis[i]==0) {sg[x]=i;break;}
24 }
25
26 bool output(int x,int now)
27 {
28     for(int i=x-1;i>=1;i--)
29      for(int j=i;j>=1;j--)
30       if((sg[i]^sg[j])==now)
31       {
32           printf("%d %d %d\n",n-x,n-i,n-j);
33           return 1;
34       }
35     return 0;
36 }
37
38 int main()
39 {
40     int kase=0;
41     for(int i=1;i<=1000;i++) get_sg(i);
42     while(1)
43     {
44         scanf("%d",&n);
45         if(n==0) break;
46         int ans=0;
47         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
48         for(int i=1;i<=n;i++) b[i]=a[n-i+1];
49         for(int i=1;i<=n;i++)
50         {
51             if(b[i]%2==1) ans^=sg[i];
52         }
53         printf("Game %d: ",++kase);
54         if(ans==0) {printf("-1 -1 -1\n");continue;}
55         int mx=0;
56         for(int i=0;(1<<i)<=ans;i++)
57             if((1<<i)&ans) mx=(1<<i);
58         for(int i=n;i>=1;i--)
59             if(b[i]!=0) {if(output(i,ans^sg[i])) break;}
60     }
61     return 0;
62 }

[UVA1378]

2016-04-17 17:12:38

时间: 2024-10-16 08:42:50

【UVA1378】A Funny Stone Game (博弈-求SG值-输出方案)的相关文章

HDU 1517 A Multiplication Game (博弈-求sg)

A Multiplication Game Problem Description Stan and Ollie play the game of multiplication by multiplying an integer p by one of the numbers 2 to 9. Stan always starts with p = 1, does his multiplication, then Ollie multiplies the number, then Stan and

UVALive 5059 Playing With Stones(求sg函数)

题意和nim游戏差不多,就是取石子的时候最多只能拿原来的一半,比如一堆5个石子最多拿两个. 先用打表的方式看出前面一部分的sg值,然后找规律来做. 打表求sg值的程序才是最重要的. #include<cstdio> #include<cstring> #define ll long long int main() { int vis[50]; int sg[50]; sg[1] = 0; for(int i = 2; i <= 30; i++) { memset(vis, 0

[nim博弈扩展 sg函数] UVALive 3668 A Funny Stone Game

题目链接: https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=242&page=show_problem&problem=1669 Root :: Regionals 2006 :: Asia - Beijing    Regionals 2006 >> Asia - Beijing 3668 - A Funny Stone Game Tim

HDU 3032 Nim or not Nim? (博弈之求SG函数)

题意:经典Nim博弈游戏变换,给你n堆石子pi,每堆有pi个石子, Alice和Bob轮流取石子,每次可以从任意一堆中拿走任意个石子,也可以将某一堆石子分成两个小堆 (每堆石子个数必须不能为0),先拿完者获胜 思路:求SG函数后找规律: SG函数定义及求法:点击打开链接 #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #in

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,然后每次取一个加两个,就相当于取掉一堆,多上两堆,这样就转

Gym 101246D Fire in the Country(dfs求SG函数)

http://codeforces.com/gym/101246/problem/D 题意: 给定一个无向有环图,大火从1点开始,每个时间点与它相邻的点也将会着火,现在有两个人轮流操作机器人,机器人从1点出发,每个人每次选择一个点走,谁最后被火烧了谁就输了. 思路: 博弈题. 我们先预处理求出每个点着火的时间点,然后根据时间点重建新图,也就是重新建一个有向无环图,原来图中相连的并且时间点相差1的相连,由时间低的连向时间高的. 接下来我们在新图上求每个点的SG值,SG值为0的点就是叶子结点,这样父

博弈之——SG模板(hdu1848&amp;&amp;hdu1536)

很久没搞博弈了.先来写个模板: 现在我们来研究一个看上去似乎更为一般的游戏:给定一个有向无环图和一个起始顶点上的一枚棋子,两名选手交替的将这枚棋子沿有向边进行移动,无法移动者判负.事实上,这个游戏可以认为是所有Impartial Combinatorial Games的抽象模型.也就是说,任何一个ICG都可以通过把每个局面看成一个顶点,对每个局面和它的子局面连一条有向边来抽象成这个"有向图游戏".下面我们就在有向无环图的顶点上定义Sprague-Garundy函数. 首先定义mex(m

博弈之——SG模板

很久没搞博弈了.先来写个模板: 现在我们来研究一个看上去似乎更为一般的游戏:给定一个有向无环图和一个起始顶点上的一枚棋子,两名选手交替的将这枚棋子沿有向边进行移动,无法移动者判负.事实上,这个游戏可以认为是所有Impartial Combinatorial Games的抽象模型.也就是说,任何一个ICG都可以通过把每个局面看成一个顶点,对每个局面和它的子局面连一条有向边来抽象成这个“有向图游戏”.下面我们就在有向无环图的顶点上定义Sprague-Garundy函数. 首先定义mex(minima

Treblecross 博弈SG值

Treblecross is a two player game where the goal is to get three X in a row on a one-dimensional board. At the start of the game all cells in the board are empty. In each turn a player puts an X in an empty cell, and if the move results three X next t