博弈问题总集第四类----Multi-SG

本文详细介绍了博弈问题中的Multi-SG概念,通过四个具体的题目——POJ2311 Cutting Game, BZOJ2940 条纹, POJ3537 Crosses and Crosses, BZOJ3576 江南乐,讲解如何应用Multi-SG求解策略。关键在于理解每次操作后状态分裂的影响,并用异或运算结合递归计算SG值,以决定游戏的胜负。" 133541475,20015694,在CentOS服务器上配置Samba文件共享,"['服务器', 'Linux', 'CentOS', 'Samba']
摘要由CSDN通过智能技术生成

一堆变多堆!

所谓Multi-SG就是每次操作完了以后一个单一游戏可能分裂成两个单一游戏。实际上这个的处理也非常方便,因为一个状态的后继变成了两个状态,而下一名玩家可以选择两个状态中的任意一个进行操作,所以影响到后继结果的应该是这两个状态构成的一个整体。那么只需要把这两个分别求出来SG值然后“加起来”也就是异或一下然后计入后继就可以了。

1、

POJ2311 Cutting Game

题意:

给出n×m的方格纸片,一次只能剪一刀,最先得到1×1纸片的人获胜。

题解:

对于博弈问题,求SG是比较关键的了
这里的状态是一个二维的,那么就考虑寻找(i,j)的直接后继状态,枚举横着剪还是竖着剪然后递归下去就好啦。

可以发现到2*2的格子是必败状态,sg=0,所以枚举k计算后继的时候从2开始

还有一个比较关键的问题就是对于一个纸片(i,j),把它剪成的两个纸片并不是独立的,也就是状态(i,j)的胜败取决于这两个纸片合起来的SG值而不是其中某一个,所以后继状态的SG值应该是这两个纸片SG值的异或值。这一段话也就是Multi-SG的解法

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int sg[205][205],w,h;
void get_sg()
{
    bool ext[40010];
    for (int x=2;x<=200;x++)
      for (int y=2;y<=200;y++)
      {
        memset(ext,0,sizeof(ext));
        for (int i=2;i+i<=x;i++)//再枚举下去就重复啦
          ext[sg[i][y]^sg[x-i][y]]=1;

        for (int j=2;j+j<=y;j++)
          ext[sg[x][j]^sg[x][y-j]]=1;

        for (int k=0;;k++)
          if (!ext[k]){sg[x][y]=k; break;}
      }
}
int main()
{
    get_sg();
    while (~scanf("%d%d",&w,&h))
      if (sg[w][h]==0) printf("LOSE\n");
      else printf("WIN\n");
}

2、

[BZOJ2940] [Poi2000] 条纹

题解:

可以类似刚才的题目考虑一下,注意每种决策要分开讨论,因为一种布料不可以放,其他两种可能还能放,Multi-SG的问题分开异或指的是当一块布料把这个棋盘分成两部分时两部分要分开异或

代码:

#include <cstdio>
#include <cstring>
using namespace std;
int sg[1005],c,z,n,m,p;
void get_sg()
{
    bool ext[1005];
    for (int i=1;i<=1000;i++) 
    {
        memset(ext,0,sizeof(ext));
        for (int j=
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值