hdu 1729 Stone Game SG函数

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1729

题意:2个玩家,有N个箱子,每个箱子的大小是Si,游戏开始前,就有一些石子在这些箱子里了。

游戏者轮流选择箱子,然后把石子放入箱子里。并且放入的石子数量不能大于原来箱子里就有的石子的数量的平方。

比如说,一个箱子里已经有了3个石头,则可以放1-9个石头(小于箱子的容量)。

当轮到某人时,不能再放石子则为输。

问能否找到一种策略使先手必赢。

学习了一下SG函数。

在公平的组合游戏中(游戏规则对于两个玩家不加区分),可以把所有可能出现的状态看作是图的节点。如果从一个状态可以通过一步转移到另一个状态,则在两点之间连一条有向边,这样就得到了一个状态图。

假设游戏不会出现平局,即状态图是有向无环图的话,所有状态可以分为两种,P态和N态。

P态:对于前一个玩家来说是必胜的。

N态:对于后一个玩家来说是必胜的。

一个状态被称为终止状态,如果当前状态下游戏不再继续进行。大部分游戏中,终止状态都是P态。就是前一个玩家走完后,游戏结束。

从定义可以知道,任意一个P态,它要么是终止状态,要么它可以转移到的状态(后继状态)都是N态,而对于任意一个N态,它至少有一个后继状态为P态。

SG函数:对于任意x,它的SG函数值g(x) = mex{g(y)|y是x的后继状态},其中mex是一个对于非负整数集合S的运算。mex(S)为S中没有出现的最小非负整数,对于一个终止状态,因为它没有后继状态。所以它的SG函数为0。

如果知道一个状态的SG函数值,则可以快速判断该状态是P态还是N态,对于一个状态们如果这个状态的SG值等于0,那么这个状态是P态(先手必败),否则就是N态。

如果有个多个组合,则sum=sg1 ^ sg2 ^ sg3 ^ ……sgn。

结论:一个游戏的初始局面是必败态当且仅当sum=0。

参考:http://blog.163.com/[email protected]/blog/static/171370086201101711276278/

思路:

参考:http://www.cnblogs.com/vongang/archive/2011/09/27/2193375.html

因为放入的石子数量不能大于原来箱子里就有的石子的数量的平方。

设每个箱子的容量为Si,已有的石子数量为Ci.

所以寻找一个p,使得p*p+p<S

1.Ci > p。那么一次放入石子数量肯定得到Si。

因为sg(S,S) = 0。

状态(S,S-1)的后继状态只有(S,S)。所以sg(S,S-1) = 1。同理sg(S,S-2) =2....

所以这种情况下sg(S,C) = S-C。先手必胜。

2. Ci = p。这种情况下。因为最多只能放p*p,且p*p+p<S。所以这个状态是P态。sg(S,C) = 0。先手必败。

3.Ci < P。这种情况下,到底是什么态就不确定了。

这里是递归求,再把p当成S,然后求sg。这里其实有一点不理解。

我是这样想的:

sg(p,c)。

如果求得x*x+x < p。

如果c = x。那么接下来的玩家就不能到(S,p)这个点。

所以下下个轮到的玩家可以达到(s,p)这个点。则下下下个玩家就不能到S。而下下下个玩家可以到S。

也就是说 先手必败。

而如果C>X。那么下一个玩家就可以达到(S,p)这个点。先手必胜。

如果C<X,继续递归。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <string>
 5 #include <algorithm>
 6 #include <cmath>
 7 using namespace std;
 8 int s, c, N, ans;
 9 int sg(int s, int c){
10     int p = sqrt(double(s));
11     while(p*p+p >= s) p--;
12     if(p < c) return s-c;
13     else if(p == c) return 0;
14     else return sg(p,c);
15 }
16 int main(){
17     int tt = 0;
18     while(scanf("%d", &N) && N){
19         int ans = 0;
20         while(N--){
21             scanf("%d%d", &s, &c);
22             ans ^= sg(s, c);
23         }
24         tt++;
25         printf("Case %d:\n", tt);
26         if(ans == 0) printf("No\n");
27         else printf("Yes\n");
28     }
29
30     return 0;
31 }
时间: 2024-10-11 17:42:33

hdu 1729 Stone Game SG函数的相关文章

hdu 3032(博弈sg函数)

题意:与原来基本的尼姆博弈不同的是,可以将一堆石子分成两堆石子也算一步操作,其它的都是一样的. 分析:由于石子的堆数和每一堆石子的数量都很大,所以肯定不能用搜索去求sg函数,现在我们只能通过找规律的办法求得sg的规律. 通过打表找规律可以得到如下规律:if(x%4==0) sg[x]=x-1; if(x%4==1||x%4==2) sg[x]=x; if(x%4==3) sg[x] = x+1. 打表代码: #include<iostream> #include<cstdio> #

hdu 1848 博弈之SG函数的使用

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1848 题目简单描述为: 1.  这是一个二人游戏;2.  一共有3堆石子,数量分别是m, n, p个:3.  两人轮流走;4.  每走一步可以选择任意一堆石子,然后取走f个:5.  f只能是菲波那契数列中的元素(即每次只能取1,2,3,5,8-等数量):6.  最先取光所有石子的人为胜者:假设双方都使用最优策略,请判断先手的人会赢还是后手的人会赢. 代码为: ? 1 2 3 4 5 6 7 8 9

HDU 1536 S-Nim 求SG函数

题意:给你n个数Nnum[ i ],表示每次只能取Nnum[ i ]个数. m个问题:每次给你 l 堆石子,每堆有num个石子,问先手是否会赢. Sample Input 2 2 5 3 2 5 12 3 2 4 7 4 2 3 7 12 5 1 2 3 4 5 3 2 5 12 3 2 4 7 4 2 3 7 12 0 Sample Output LWW WWL 经典Nim游戏,找出SG就可以了. 至于如何找SG,这里有详细的 点我 #include<cstdio> #include<

hdu 1729 Stone Game

Stone Game HDU - 1729 题意: 给定n个箱子,每个箱子的容量为si,每个箱子里最初有ci个石子,每次放入石子不能超过放入前的石子数的平方,谁无法继续放入石子就算输. /* 这是个SG函数的基础题?并不是的吧.. 求一个t使t+t*t=si,那么 1.当ci>t时,是必胜态,可以一次性放满箱子,即(si,si). 2.当ci==t时,即便只放一个,下一个状态t+1+(t+1)*(t+1)一定能放满箱子必胜,所以ci==t这个状态必败. 3.当ci=si-t,同样的方法判断必胜必

HDU 5724 Chess(SG函数)

Chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2605    Accepted Submission(s): 1092 Problem Description Alice and Bob are playing a special chess game on an n × 20 chessboard. There are s

HDU 1729 Stone Game 石头游戏 (Nim, sg函数)

题意:有n个盒子,每个盒子可以放一定量的石头,盒子中可能已经有了部分石头.假设石头无限,每次可以往任意一个盒子中放石头,可以加的数量不得超过该盒中已有石头数量的平方k^2,即至少放1个,至多放k^2个. 思路:跟常规nim的区别就是加了个限制“每次加的量不超平方”.盒子容量上限是100万,那么就不能直接计算SG了,会超时.sg打表后找规律.根据剩下多少个空位来决定sg值.都是0123456这样子递增的,碰到不能一次加满就变为0,然后继续递增,一直这样. 我的方案是,对于每个盒子大小,找到除了自己

HDU1729 Stone Game (SG函数)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1729 题意: 又n个盒子,每个盒子的可以放 S个石头,里面已经有的石头的个数为C: 每次可以放的石头的个数不超过C*C.先手胜的输出Yes,后手胜输出No. 分析: 必败的状态很好找 当C + C * C < S && (C + 1) + (C + 1) * (C + 1) > = S; 然后我们对于每一组(c,s)来寻找他的必败状态. 枚举for(i = 1 ; i + i *

hdu 3980 Paint Chain sg函数

题目链接 给一个长度为n的环, 两个人轮流涂色, 每次涂m个连续的, 无法继续涂了就输. 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define pb(x) push_back(x) 4 #define ll long long 5 #define mk(x, y) make_pair(x, y) 6 #define lson l, m, rt<<1 7 #define mem(a) memset(a, 0, sizeo

hdu 1079 Calendar Game sg函数

Calendar Game Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 2766    Accepted Submission(s): 1594 Problem Description Adam and Eve enter this year’s ACM International Collegiate Programming Con