zoukankan      html  css  js  c++  java
  • 【UVA1378】A Funny Stone Game (博弈-求SG值-输出方案)

    【题目】

    Description

    The funny stone game is coming. There are n piles of stones, numbered with 0, 1, 2, ..., n − 1. Two
    persons pick stones in turn. In every turn, each person selects three piles of stones numbered i, j, k
    (i < j, j ≤ k and at least one stone left in pile i). Then, the person gets one stone out of pile i, and
    put one stone into pile j and pile k respectively. (Note: if j = k, it will be the same as putting two
    stones into pile j). 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 integer n
    (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 pile
    n − 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: i j k’. 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 of
    i, 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

    【题目翻译】

      David 玩一个石子游戏。游戏中,有n堆石子,被编号为0..n-1。两名玩家轮流取石子。每一轮游戏,每名玩家选取3堆石子i,j,k(i<j,j<=k,且至少有一枚石子在第i堆石子中),从i中取出一枚石子,并向j,k中各放入一枚石子(如果j=k则向k中放入2颗石子)。最先不能取石子的人输。

       请编程帮助David。

       石子堆的个数不会超过23,每一堆石子不超过1000个。

     

    【分析】

      首先,假设第i堆有xi个石子,那么可以先把xi%2。

      因为在同一堆中的两颗石子是一模一样的。对方对这颗石子做什么,你就可以对另外一颗石子做同样的事,相当于这两颗一样的石子不存在。

      因为每颗石子可以变成两颗放到后面去,也就是说它的转移状态和它的编号有关。

      可以将每一颗石子看作是一堆石子,如果它是第p堆中的石子,把么它所代表的这堆石子的个数为n-1-p。

      因为石子堆是互不干扰的,因此这个游戏可以看作由若干个只有一堆石子的游戏组成。(把其单独考虑开来)

      求它能到达的子状态的尼姆和更新自己的sg值即可。跟扫楼梯一题差不多,即使这堆石子的个数为偶数个,他可能还是有用的,即可以拆分也把状态改变为平衡状态的,要把这个也考虑上。(好像说得不是很清楚,具体看代码吧~~)

     

    代码如下:(看错数据范围了,懒得改了,就酱吧~)

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 #include<queue>
     7 using namespace std;
     8 #define Maxn 1010
     9 
    10 int n;
    11 int a[2*Maxn],b[2*Maxn],sg[2*Maxn];
    12 bool vis[2*Maxn];
    13 
    14 void get_sg(int x)
    15 {
    16     memset(vis,0,sizeof(vis));
    17     for(int i=1;i<x;i++)
    18      for(int j=i;j<x;j++)
    19      {
    20          vis[sg[i]^sg[j]]=1;
    21      }
    22     for(int i=0;i<=2000;i++) 
    23         if(vis[i]==0) {sg[x]=i;break;}
    24 }
    25 
    26 bool output(int x,int now)
    27 {
    28     for(int i=x-1;i>=1;i--)
    29      for(int j=i;j>=1;j--)
    30       if((sg[i]^sg[j])==now)
    31       {
    32           printf("%d %d %d
    ",n-x,n-i,n-j);
    33           return 1;
    34       }
    35     return 0;
    36 }
    37 
    38 int main()
    39 {
    40     int kase=0;
    41     for(int i=1;i<=1000;i++) get_sg(i);
    42     while(1)
    43     {
    44         scanf("%d",&n);
    45         if(n==0) break;
    46         int ans=0;
    47         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    48         for(int i=1;i<=n;i++) b[i]=a[n-i+1];
    49         for(int i=1;i<=n;i++)
    50         {
    51             if(b[i]%2==1) ans^=sg[i];
    52         }
    53         printf("Game %d: ",++kase);
    54         if(ans==0) {printf("-1 -1 -1
    ");continue;}
    55         int mx=0;
    56         for(int i=0;(1<<i)<=ans;i++)
    57             if((1<<i)&ans) mx=(1<<i);
    58         for(int i=n;i>=1;i--) 
    59             if(b[i]!=0) {if(output(i,ans^sg[i])) break;}
    60     }
    61     return 0;
    62 }
    [UVA1378]

    2016-04-17 17:12:38

  • 相关阅读:
    小白学 Python 数据分析(21):pyecharts 好玩的图表(系列终篇)
    小白学 Python 数据分析(20):pyecharts 概述
    小白学 Python 数据分析(19):Matplotlib(四)常用图表(下)
    小白学 Python 数据分析(18):Matplotlib(三)常用图表(上)
    在 ASP.NET Core 程序启动前运行你的代码
    在 ASP.NET Core 项目中使用 MediatR 实现中介者模式
    在 ASP.NET Core 项目中使用 AutoMapper 进行实体映射
    [Vue 牛刀小试]:第十七章
    或许是你应该了解的一些 ASP.NET Core Web API 使用小技巧
    [Vue 牛刀小试]:第十六章
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/5401461.html
Copyright © 2011-2022 走看看