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 in pilei).
Then, the person gets one stone out of pilei, and put one stone into pile
j and pile k respectively. (Note: ifj =
k, it will be the same as putting two stones into pilej). 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 integern (
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 pilen - 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:ijk".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 ofi,
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
题意:有n堆石头,编号为0-n-1,第i堆初始有si个石头,两个游戏者轮流操作,每次可以选3堆i,j,k,使得i<j<=k,且第i堆至少还剩一个石子,然后从第i堆拿走一个石子
再往第j堆和第k堆各放一个石子(j和k可以一样),判断先手必胜还是必败,如果必胜,输出字典序最小的一个操作(i,j,k)。
思路:可以把每个石子看作是独立的游戏,然后我们从左到右重现排列成n-1,n-2.....0,这样方便我们SG状态的转移,所以我们就可以枚举每个i的后继状态sg[j]^sg[k]了,最后判断一下
操作一次后的SG值是不是为0,也就是必败
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 105;

int n, a[maxn], sg[maxn], vis[maxn];

void init() {
	for (int i = 0; i <= 23; i++) {
		memset(vis, 0, sizeof(vis));
		for (int j = 0; j < i; j++)
			for (int k = j; k < i; k++)
				vis[sg[k]^sg[j]] = 1;
		for (int j = 0; ; j++)
			if (!vis[j]) {
				sg[i] = j;
				break;
			}
	}
}

int main() {
	init();
	int cas = 1;
	while (scanf("%d", &n) != EOF && n) {
		int ans = 0;
		for (int i = 0; i < n; i++) {
			scanf("%d", &a[i]);
			if (a[i] & 1)
				ans ^= sg[n-1-i];
		}
		printf("Game %d: ", cas++);
		if (ans == 0)
			printf("-1 -1 -1\n");
		else {
			int flag = 0;
			for (int i = 0; i < n; i++) {
				if (a[i] == 0)
					continue;
				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);
							flag = 1;
							break;
						}
					if (flag)
						break;
				}
				if (flag)
					break;
			}
		}
	}
	return 0;
}

时间: 2024-11-12 23:25:42

UVA - 1378 A Funny Stone Game (SG定理)的相关文章

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堆不能移为止.首先是考虑每堆石子其实是独立的一个子游戏,堆与堆之间不相互影响.然后就是个

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(博弈)

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

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

UVA - 10561 Treblecross (SG定理)

Treblecross is a two player gamewhere the goal is to get three X in a row on a one-dimensional board. At the startof the game all cells in the board is empty. In each turn a player puts a X in an empty cell, and if that results in there beingthree X

(转载)--SG函数和SG定理【详解】

在介绍SG函数和SG定理之前我们先介绍介绍必胜点与必败点吧. 必胜点和必败点的概念: P点:必败点,换而言之,就是谁处于此位置,则在双方操作正确的情况下必败. N点:必胜点,处于此情况下,双方操作均正确的情况下必胜. 必胜点和必败点的性质: 1.所有终结点是 必败点 P .(我们以此为基本前提进行推理,换句话说,我们以此为假设) 2.从任何必胜点N 操作,至少有一种方式可以进入必败点 P. 3.无论如何操作,必败点P 都只能进入 必胜点 N. 我们研究必胜点和必败点的目的时间为题进行简化,有助于

SG函数和SG定理【详解】

在介绍SG函数和SG定理之前我们先介绍介绍必胜点与必败点吧. 必胜点和必败点的概念: P点:必败点,换而言之,就是谁处于此位置,则在双方操作正确的情况下必败. N点:必胜点,处于此情况下,双方操作均正确的情况下必胜. 必胜点和必败点的性质: 1.所有终结点是 必败点 P .(我们以此为基本前提进行推理,换句话说,我们以此为假设) 2.从任何必胜点N 操作,至少有一种方式可以进入必败点 P. 3.无论如何操作,必败点P 都只能进入 必胜点 N. 我们研究必胜点和必败点的目的时间为题进行简化,有助于

组合游戏 - SG函数和SG定理

在介绍SG函数和SG定理之前我们先介绍介绍必胜点与必败点吧. 必胜点和必败点的概念: P点:必败点,换而言之,就是谁处于此位置,则在双方操作正确的情况下必败. N点:必胜点,处于此情况下,双方操作均正确的情况下必胜. 必胜点和必败点的性质: 1.所有终结点是 必败点 P .(我们以此为基本前提进行推理,换句话说,我们以此为假设) 2.从任何必胜点N 操作,至少有一种方式可以进入必败点 P. 3.无论如何操作,必败点P 都只能进入 必胜点 N. 我们研究必胜点和必败点的目的时间为题进行简化,有助于

HDU5795A Simple Nim SG定理

A Simple Nim Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 980    Accepted Submission(s): 573 Problem Description Two players take turns picking candies from n heaps,the player who picks the l