硬币游戏2&&Cutting Game——Grundy值

Grundy值

当前状态的Grundy值就是除任意一步所能转移到的状态的Grundy值以外的最小非负整数,

以硬币问题一为例,可写成:

int init_grundy()
{
    sg[0] = 0;
    for(int i = 1;i <= x;i++)   //递推求前x个SG值
    {
        set<int>st;
        for(int j = 0;j < k;j++)
            if(a[j] <= i) st.insert(sg[i - a[j]]);

        int g = 0;
        while(st.count(g))  g++;
        sg[i] = g;
    }
}

Grundy值有什么用呢?

它的作用是巨大的,利用它,不光可以解决这个问题,其它许多问题都可以转换成前面介绍的Nim问题,即问题的解等于子问题的异或和。

Nim问题为什么等于异或和之前口胡过,这些问题为什么等于子问题的Grundy值的异或和呢?

根据Grundy的定义,先看下Grundy的性质(与Nim对比):

  • Nim中有x颗石子的石子堆,能够转移成0, 1, 2, ..., x-1可石子的石子堆
  • 从Grundy值为x的状态出发,也能转移到Grundy值为0, 1, 2, ,,,,, x-1的状态

也就不难理解为什么是异或和了:当必败态为Grundy异或和为0是,能保证必败态只能变成必胜态;必胜态可以转成必败态。

为了保证Grundy值为x的状态能转移为小于x的状态,Grundy的定义设为不在子问题Grundy值中的最小值(也就是说小于x的Grundy值都存在于子问题中)//好像有点循环论证,,,醒醒,这也能叫证明,,,个人理解吧

也不难发现,Nim问是Grundy问题的特例,其单堆的Grundy值为x。

例题

1、硬币游戏2

就是个堆Grundy值得异或和,异或和为0先手必败,否则先手必胜。

2、Cutting Game

题目:有一张 $w \times h$ 个格子的长方形纸,两个人轮流切割,水平或者垂直的切成两部分,最小切出单个格子($1 \times 1$)的一方获胜。当双方都采取最佳策略时,谁会获胜?

分析:

这样会发生分割的游戏,也能够计算Grundy值。(为啥啊??)

当一张 $w \times h$ 的纸张分割成两张时,假设所得的纸张的Grundy值分别为 $g_1$ 和 $g_2$,则这两张纸对应的状态的Geundy值为 $g_1 \ XOR \ g_2$。

另外,易知,一旦切割出长或宽为1时,下一步就一定能够切出 $1 \times 1$的纸张,所以知道此时必败。因此切割纸张时总要保证长和宽至少为2.

不然,grundy(2,2) 时 st{ grundy(1,2)^grundy(1,2), grundy(2,1)^grundy(2,1) },则sg[2]=1先手必胜;而实际上先手必败。

(为什么硬币问题不要考虑转译成必败态,不懂,哪个大佬能教教我)

#include<cstdio>
#include<set>
#include<cstring>
using namespace std;

const int maxw = 200+10;
const int maxh = 200+10;
int sg[maxw][maxh];

int grundy(int w, int h)
{
    //printf("%d %d\n", w, h);
    int& ret = sg[w][h];
    if(ret != -1)  return ret;
    if(w==1 || h==1)  return ret=1;

    set<int>st;
    for(int i = 2;i < w-1;i++)  st.insert(grundy(i, h) ^ grundy(w-i, h));
    for(int i = 2;i < h-1;i++)  st.insert(grundy(w, i) ^ grundy(w, h-i));
    ret = 0;
    while(st.count(ret))  ret++;
    return ret;
}

int w, h;

int main()
{
    memset(sg, -1, sizeof(sg));
    while(scanf("%d%d", &w, &h) == 2)
    {
        if(grundy(w, h)==0)  printf("LOSE\n");
        else  printf("WIN\n");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/lfri/p/11625816.html

时间: 2024-11-06 07:32:57

硬币游戏2&&Cutting Game——Grundy值的相关文章

4.1.6 Grundy数-硬币游戏2

Problem Description: Alice 和 Bob 在玩一个游戏.给定 k 个数字 a1,a2,--,ak.一开始,有n堆硬币,每堆各有 Xi 枚硬币.Alice 和 Bob 轮流选出一堆硬币,从中取出一些硬币.每次所选硬币的枚数一定要在 a1,a2,--,ak 当中.Alice先取,取光硬币的一方获胜.当双方都采取最优策略时,谁会获胜?题目保证a1,a2--中一定有1. 1<=n<=1000000 1<=k<=100 1<=Xi,ai<=10000 In

poj 2311 Cutting Game nim与状态的grundy值

题意: 给一个w*h的矩形,两人轮流只能沿格子的边缘横剪或竖剪,最先剪出1*1的格子的人获胜,问先手必胜还是必败. 分析: 此题要求对grundy值有理解.一个全局状态的grundy值是对游戏中某个状态的有效的描述,grundy值描述了当前状态的所有后继状态,比如n堆石子的nim游戏的grundy值是a1^a2^...an. 代码: //poj 2311 //sep9 #include <iostream> #include <set> using namespace std; c

博弈论:寻找先手必胜策略——Grundy值

选修了人工智能课程,老师布置了调研任务:Grundy,开始看了一些资料并没有看懂. 后来找到了一篇文,写的很棒,里面有好多博弈相关的问题与分析,分享出来给大家: http://endless.logdown.com/posts/2014/05/05/find-out-the-winning-strategies-of-the-game-nim-and-grundy-number-notes 这个服务器可能是外国的?打开的很慢,不要认为自己的网炸了...哈哈哈 下面就贴一点自己为了做海报(Grun

博弈——翻硬币游戏

转自:http://blog.sina.com.cn/s/blog_8f06da99010125ol.html 翻硬币游戏 一般的翻硬币游戏的规则是这样的: N 枚硬币排成一排,有的正面朝上,有的反面朝上.我们从左开始对硬币按1 到N 编号. 第一,游戏者根据某些约束翻硬币,但他所翻动的硬币中,最右边那个硬币的必须是从正面翻到反面.例如,只能翻3个硬币的情况,那么第三个硬币必须是从正面翻到反面.如果局面是正正反,那就不能翻硬币了,因为第三个是反的. 第二,谁不能翻谁输. 有这样的结论:局面的SG

HDU 3537 Mock Turtles型翻硬币游戏

题目大意: 每次可以翻1个或者2个或者3个硬币,但要保证最右边的那个硬币是正面的,直到不能操作为输,这题目还有说因为主人公感情混乱可能描述不清会有重复的硬币说出,所以要去重 这是一个Mock Turtles型翻硬币游戏 下面是对这个类型游戏的讲解 约束条件6:每次可以翻动一个.二个或三个硬币.(Mock Turtles游戏) 初始编号从0开始. 当N==1时,硬币为:正,先手必胜,所以sg[0]=1. 当N==2时,硬币为:反正,先手必赢,先手操作后可能为:反反或正反,方案数为2,所以sg[1]

1289 大鱼吃小鱼 1305 Pairwise Sum and Divide 1344 走格子 1347 旋转字符串 1381 硬币游戏

1289 大鱼吃小鱼 有N条鱼每条鱼的位置及大小均不同,他们沿着X轴游动,有的向左,有的向右.游动的速度是一样的,两条鱼相遇大鱼会吃掉小鱼.从左到右给出每条鱼的大小和游动的方向(0表示向左,1表示向右).问足够长的时间之后,能剩下多少条鱼? Input 第1行:1个数N,表示鱼的数量(1 <= N <= 100000). 第2 - N + 1行:每行两个数A[i], B[i],中间用空格分隔,分别表示鱼的大小及游动的方向(1 <= A[i] <= 10^9,B[i] = 0 或 1

软工作业2:硬币游戏——代码的分析与改进

目的: Python 程序阅读理解 学习Python 编码风格指南中译版(Google SOC), 改进Python程序 如何设计游戏规则,使得慈善事业可持续. 地铁口放置硬币箱(初始值500硬币),顾客可取.可放.请设计一组规则,使得该钱箱永远有钱取(尽量符合实际) 参考:地铁口钱箱 作业步骤: step 1: fork 老师的仓库 +硬币游戏:http://git.oschina.net/juking2017/Game.git 将其 fork 到自己的码云仓库. step2:clone 到本

软工作业: (2)硬币游戏—— 代码分析与改进

软工作业: (2)硬币游戏-- 代码分析与改进 一.作业要求 1.Python 程序阅读理解 2.学习Python 编码风格指南中译版(Google SOC)(http://blog.csdn.net/damotiansheng/article/details/43867175),改进Python程序 3.设计游戏规则,使得慈善事业可持续. 地铁口放置硬币箱(初始值500硬币),顾客可取.可放.请设计一组规则,使得该钱箱永远有钱取(尽量符合实际) 注:参考http://www.cnblogs.c

2017(秋)软工作业: (2)硬币游戏—— 代码分析与改进

要求: Python 程序阅读理解 学习Python 编码风格指南中译版(Google SOC), 改进Python程序 如何设计游戏规则,使得慈善事业可持续. 地铁口放置硬币箱(初始值500硬币),顾客可取.可放.请设计一组规则,使得该钱箱永远有钱取(尽量符合实际) step 1: fork 老师的仓库 +硬币游戏:http://git.oschina.net/juking2017/Game.git 将其 fork 到你的码云仓库,登录码云点击右上角fork即可.     step2:将自己仓