状态压缩与求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;
}


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

HDU5724(多校第一场)——Chess(sg函数,状态压缩)

Chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Su...

hdu5724——chess(博弈)(状态压缩dp+sg函数)

Problem Description: Alice and Bob are playing a special chess game on an n × 20 chessboard. There ...

【状态压缩DP】函数依赖

函数依赖 【问题描述】 设 R(U)是一个属性集 U 上的关系模式,X 和 Y 是 U 的子集。若对于 R(U) 的任意一个可能的关系 r,r 中不可能存在两个元组在 X 上的属性值相等,而...

【状态压缩搜索】函数依赖

【问题描述】 设 R(U)是一个属性集U 上的关系模式,X 和Y 是U 的子集。若对于R(U)的任意一个可能的关系r,r 中不可能存在两个元组在X 上的属性值相等,而在Y 上的属性值不等, 则称 “X...
  • Whjpji
  • Whjpji
  • 2012年04月07日 14:34
  • 441

POJ2288Islands and Bridges(状态压缩DP,求最大路和走条数)

Islands and Bridges Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 884...

状态压缩讲稿

  • 2013年05月03日 15:10
  • 498KB
  • 下载

acm 算法 动态规划之状态压缩

  • 2010年07月28日 11:25
  • 396KB
  • 下载

HDOJ4336Card Collector【概率dp求期望+状态压缩】

Card Collector Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:状态压缩与求sg函数
举报原因:
原因补充:

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