状态压缩与求sg函数

原创 2016年08月28日 19:46:21

题目:hdu5724

题意:给定一个n*20的棋盘,棋盘上有若干棋子。如果一颗棋子右侧为空,则只可以向右移动一格,若非空,则可以移到第一个空的位置,两人轮流操作,不能操作者为输,问先者是否有必胜策略

解答:注意到棋盘只有20列,则可以用状态压缩存储当前的状态。预处理出所有状态的sg值。然后n个抑或一下就好了。

我的代码(每次递归求出当前的sg值):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN = 1 << 21;
int sg[MAXN];
int getnew(int a,int u,int v)
{
    return (a - (1 << u) + (1 << v));
}
int getsg(int a)
{
    if(sg[a] != -1)
        return sg[a];
    int vis[20];
    memset(vis,0,sizeof(vis));
    int ok = 1;
    for(int i = 0;i < 19;i++)
    {
        int temp = 1 << i;
        if(a & temp)
        {
           for(int j = i + 1;j <= 19;j++)
           {
               if(!(a & (1 << j)))
               {
                   vis[getsg(getnew(a,i,j))] = 1;
                   break;
               }
           }
        }
    }
    for(int i = 0;;i++)
    {
        if(!vis[i])
        {
            sg[a] = i;
            return i;
        }
    }
}
void init()
{
    memset(sg,-1,sizeof(sg));
    for(int i = 0;i <= ((1 << 20) - 1);i++)
    {
        sg[i] = getsg(i);
    }
}
int main()
{
    int T,t,n;
    scanf("%d",&T);
    init();
    while(T--)
    {
        int ans = 0;
        scanf("%d",&n);
        while(n--)
        {
            int k;
            int tmp = 0;
            scanf("%d",&k);
            while(k--)
            {
                scanf("%d",&t);
                tmp += 1<<(t-1);
            }
            ans ^= sg[tmp];
        }
        if(ans == 0)
            puts("NO");
        else
            puts("YES");
    }
    return 0;
}

别人的代码(从后往前求sg值。因为求状态值较小的值,它的后继状态的值肯定比当前的状态值大。所以从后往前求就可以了,不需要递归)

#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
const int MAXN = 1 << 20;
int n;
int sg[MAXN];
int vis[20];
int getsg(int x)
{
    memset(vis,0,sizeof(vis));
    for(int i = 0;i < 20;i++)
    {
        if(x&(1 << i))
        {
            for(int j = i + 1;j < 20;j++)
            {
                if(!(x&(1 << j)))
                {
                    vis[sg[x^(1 << i)^(1 << j)]] = 1;
                }
            }
        }
    }
    for(int i = 0;i < 20;i++)
        if(!vis[i])
        return i;
}

int main()
{
    int t;
    scanf("%d",&t);
    for(int i = (1 << 20)-1;i >= 0;i--)
        sg[i] = getsg(i);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        int ans = 0;
        for(int i = 0;i < n;i++)
        {
            int q;
            scanf("%d",&q);
            int m = 0;
            while(q--)
            {
                int x;
                scanf("%d",&x);
                m = m | (1 << (x-1));
            }
            ans = ans ^ sg[m];
        }
        if(ans)
            puts("YES");
        else
            puts("NO");
    }
    return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

博弈之sg函数(模板)

组合博弈的通解就是sg函数,学习了sg函数之后一直没有咋用过。 学习博弈的可以在nyoj上面做10道取石子题目,作为了对博弈也就有一定理解了。 用的时候注意初始的时候只要初始sg[0]=0; 其他都通...
  • y990041769
  • y990041769
  • 2014年03月17日 20:26
  • 8247

SG函数的详细解释

SG函数可以说是博弈论中很重要的运用,有了SG函数就可以解决很多很难解决的博弈问题,也是解决例如nim博弈和翻硬币博弈的一些基础。 入门一: 首先来玩个游戏,引用杭电课件上的: ...
  • beyhhhh
  • beyhhhh
  • 2015年07月14日 20:38
  • 551

博弈论 SG函数从懵逼到入门 SG模板 hdu1848

 摘自piaocoder的博客: 首先定义mex(minimal excludant)运算,这是施加于一个集合的运算,表示最小的不属于这个集合的非负整数。例如 mex{0,1,2,4...
  • yizhangbiao
  • yizhangbiao
  • 2016年07月22日 10:03
  • 1398

sg函数模板(打表)

int sg[maxn];//sg[n] n表示每堆数量 int s[k];//每次能取的值,下标从0开始,0 ~ k-1,必须有序,可以sort(s,s+k); bool vis[maxn]; co...
  • elbadaernu
  • elbadaernu
  • 2017年04月17日 22:16
  • 380

组合游戏 - SG函数和SG定理

组合游戏的和通常是很复杂的,所以我们介绍一种新工具,可以使组合问题变得简单————SG函数和SG定理。 Sprague-Grundy定理(SG定理):         游戏和的SG函数等于各个游戏SG...
  • luomingjun12315
  • luomingjun12315
  • 2015年05月07日 08:09
  • 8140

Nim 游戏和 SG 函数

Nim游戏Nim游戏定义Nim游戏是组合游戏(Combinatorial Games)的一种,准确来说,属于“Impartial Combinatorial Games”(以下简称ICG)。满足以下条...
  • Zarth
  • Zarth
  • 2016年04月30日 23:12
  • 873

博弈sg函数

sg函数(个人认为还是用于三种方法都无法解决的情况,如按特殊数字取石子) 我们把整个博弈过程抽象为有向无环图 1.      几项准备工作: mex求最小非负整数mex{} = 0,mex{0,1,2...
  • qq_30241305
  • qq_30241305
  • 2016年03月07日 15:36
  • 1167

博弈论 SG函数

别被文章长度吓到,学会博弈(SG)只用看前1/10。 鉴于讲明白博弈要写好多字,于是找了些论文拼凑,对疑难点加了注释并配上“美图”助解。 Nim游戏 重点结论:对于一个Nim游戏的局面(a1,a2,....
  • strangedbly
  • strangedbly
  • 2016年04月12日 21:36
  • 7574

博弈之SG函数(详解为什么异或可以得出结果)

给定一个有向无环图和一个起始顶点上的一枚棋子,两名选手交替的将这枚棋子沿有向边进行移动,无法移 动者判负。事实上,这个游戏可以认为是所有Impartial Combinatorial Games的...
  • hndu__lz
  • hndu__lz
  • 2017年03月13日 20:40
  • 527

博弈 SG函数

为什么要学习这个呢?因为每次看到题解的第一句话总是这种的: 水题,简单题,模板题,打表题 然后,第二句话,就是结论,比如sg【x】等于(然后一个分类),就得到了公式 最后就是把所有的亦或起来,就得到了...
  • kevin66654
  • kevin66654
  • 2016年08月10日 17:11
  • 392
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:状态压缩与求sg函数
举报原因:
原因补充:

(最多只允许输入30个字)