zoukankan      html  css  js  c++  java
  • 4.1.7 Cutting Game(POJ 2311)

    Problem description:

      两个人在玩如下游戏。

      准备一张分成 w*h 的格子的长方形纸张,两人轮流切割纸张。要沿着格子的边界切割,水平或者垂直地将纸张切成两部分。切割了n次之后就得到了n+1张纸,每次都选择切得的某一张纸再进行切割。首先切出只有一个格子的纸张(1*1的各自组成的纸张)的一方获胜。当双方都采取最优策略时,先手是必胜,还是必败?

      2<=w,h<=200

    Input:

      w=2,  h=2

    Out put:

      LOSE

      前面的硬币问题2中,有n堆硬币,我们求出每堆硬币的Grundy值,再根据它们XOR后的值判断胜负。另一方面,这个游戏中,初始只有一张纸,纸张的数量随切割增加。这样会发生分割的游戏,也能够计算Grundy值(XOR运算满足结合律)。

      当w*h的纸张分成两张时,假设所分得的纸张的Grundy值分别为g1和g2,则这两张纸对应的状态的Grundy值可以表示为g1 XOR g2。

      在Nim中,不论有几堆石子,初始状态是怎么样的,只有XOR的结果相同,那么对胜负是没有影响的,这里也是同样的,只要Grundy值相同,即便发生切割,只要对分割后的各部分取XOR,就可以用这一个Grundy值来代表几个游戏复合而成的状态,Grundy值也可以同样计算。

      了解了会发生分割的游戏的处理方法之后,只要像之前的问题一样,枚举所有一步能转移到的状态的Grundy值,就能够计算Grundy值了。

      另外,切割纸张时,一旦切割出了长或宽为1 的纸张,下一步就一定能够切割出1*1的纸张,所以可以知道此时必败。因此,切割纸张时,总要保证长和宽至少为(无论如何都不能保证是,就是必败态。此时根据Grundy值的定义,不需要特别处理其Grundy值也是)。

    const int MAX_WH =200;
    //记忆化搜索所用的数组,程序开始执行时全部初始化为-1
    int mem[MAX_WH][MAX_WH];
    int grundy(int w,int h){
        if(mem[W][H]!=-1) return mem[w][h];
        set<int> s;
        for(int i=2;w-i>=2;i++)
            s.insert(grundy(i,h)^grundy(w-i,h));
        for(int i=2;h-i>=2;i++)
            s.insert(grundy(w,i)^grundy(w,h-i));
        int res=0;
        while(s.count(res)) res++;
        return mem[w][h]=res;
    } 
    void solve(int w,int h){
        if(grundy(w,h)!=0) puts("WIN");
        else puts("LOSE");
    }
    View Code
  • 相关阅读:
    递归算法的时间复杂度
    5分钟了解lucene全文索引
    Codeforces Round #234A
    快速排序法
    构造方法、类的初始化块以及类字段的初始化顺序
    Java之方法重载篇(我重载了,你要如何来调用我。。)
    突如其来的&amp;quot;中断异常&amp;quot;,我(Java)该如何处理?
    一个简单的wed服务器SHTTPD(4)————SHTTPD支持CGI的实现
    一个简单的wed服务器SHTTPD(3)————SHTTPD多客户端支持的实现
    一个简单的wed服务器SHTTPD(2)———— 客户端请求分析
  • 原文地址:https://www.cnblogs.com/astonc/p/9955220.html
Copyright © 2011-2022 走看看