• HDU1536 S-Nim


    题目链接:https://vjudge.net/problem/HDU-1536

    题目大意:

      给一个数集(S),稍微修改(Nim)游戏的规则:原本是能在一堆里面取任意个数的石子,现在变成只能取(n(n in S))个石子,当没得取石子时判负。对于给定的局面,问先手的胜负条件。

    知识点:  博弈论

    解题思路:

      首先引用贾志豪的论文《组合游戏略述——浅谈SG游戏的若干拓展及变形》里面介绍的几个概念、定理:

      游戏的和:考虑任意多个同时进行的(SG)组合游戏,这些(SG)组合游戏的和是这样一个(SG)组合游戏,在它进行的过程中,游戏者可以任意挑选其中的一个单一游戏进行决策,最终,没有办法进行决策的人输。

      在我们每次只能进行一步操作的情况下,对于任何的游戏的和,我们若将其中的任一单一(SG)组合游戏换成数目为它的(SG)值的一堆石子,该单一(SG)组合游戏的规则编程取石子游戏的规则(可以任意取,甚至取完),则游戏的和的胜负情况不变。

      由以上两条得到启发:我们可以把题目中的这个(S-Nim)游戏中的每一堆石子看成一个独立的取石子游戏(只能取数集(S)中的数目的石子),算出每个独立游戏的(SG)值,整个游戏的(SG)值即为各个子游戏的(SG)值的异或和。

      而(SG)函数有如下性质:

      (1)对于任意的局面,如果它的(SG)值为(0),那么它的任何一个后继局面的(SG)值不为(0);

      (2)对于任意的局面,如果它的(SG)值不为(0),那么它一定有一个后继局面的(SG)值为(0)。

      由此我们不难推出:当(SG)值为(0)时,先手必败;否则先手必胜。

    AC代码:

     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 int S[105],k;
     5 int sg[10005];
     6 int inp[105];
     7 bool vis[10005];
     8 void dfs(int rt){   //DFS求rt的SG值,注意要加记忆化。
     9     if(sg[rt]!=-1)  return;
    10     for(int i=0;i<k&&rt-S[i]>=0;i++){
    11         if(sg[rt-S[i]]==-1) dfs(rt-S[i]);
    12     }
    13     for(int i=0;i<=k;i++)  vis[i]=false;
    14     for(int i=0;i<k&&rt-S[i]>=0;i++)
    15         vis[sg[rt-S[i]]]=true;
    16     for(int i=0;i<=rt;i++){
    17         if(!vis[i]){
    18             sg[rt]=i;
    19             return;
    20         }
    21     }
    22 }
    23 int main(){
    24     int l;
    25     while(scanf("%d",&k)==1&&k){
    26         for(int i=0;i<=10000;i++)   sg[i]=-1;
    27         for(int i=0;i<k;i++)    scanf("%d",&S[i]);
    28         sort(S,S+k);
    29         for(int i=0;i<S[0];i++) sg[i]=0;
    30         int m;
    31         scanf("%d",&m);
    32         while(m--){
    33             scanf("%d",&l);
    34             int tmp=0;
    35             for(int i=0;i<l;i++){
    36                 scanf("%d",&inp[i]);
    37                 dfs(inp[i]);
    38                 tmp^=sg[inp[i]];
    39             }
    40             if(tmp==0)  printf("L");
    41             else    printf("W");
    42         }
    43         printf("
    ");
    44     }
    45 
    46     return 0;
    47 }

      

    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    呵呵,庆祝偶的blog开张了~
    把.NET程序部署到没有安装.NETFramwork的机器上
    1842005 日记
    So In Love
    windows网络编程经典入门
    水木穿梭
    c++智能指针的使用,shared_ptr,unique_ptr,weak_ptr
    c++的左值(lvalue),右值(rvalue),移动语义(move),完美转发(forward)
    (一)深入理解JVM第三版JDK的发展历史
    处理在多参数情况下分页参数的完整性
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/8433266.html
Copyright © 2020-2023  润新知