hdu 1809(A New Tetris Game(2)) 字符串hash+sg函数+DP

本文介绍了一道关于俄罗斯方块的游戏问题,利用博弈论中的SG函数解决填充图形问题。难点在于状态转换及避免重复搜索,采用字典树进行状态离散化处理。

题目链接:点击打开链接

题意很简单,用俄罗斯方块填充图形,有些格子有障碍物,最后一个放下方块的人取得胜利,懒得介绍了~

考点是博弈论sg函数的用法~~这个题目难点在于是最多能放下10个俄罗斯正方形~50*50的布局使得单纯的状态压缩无法记录已经搜索过的值,但是初始状态能转化到的所有子状态数量又是有限的~所以这里要用到字符串的hash,我这里是直接用的字典树将状态离散化的~~附上代码~~

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN=60;
char chess[MAXN][MAXN];
int n,m;
void print()
{
    printf("Debug\n");
    for(int i=0;i<n;i++)
        puts(chess[i]);
}
struct hashCode
{
    const static int SIZE=100000;
    struct node_t
    {
        node_t *son[2];
        int idx;
    }Node[SIZE];
    int toUsed;
    inline void init()
    {
        toUsed=1;
        memset(Node,0,sizeof(node_t));
    }
    inline node_t* _NewNode()
    {
        memset(Node+toUsed,0,sizeof(node_t));
        return Node+toUsed++;
    }
    inline void insert(const char word[],int data)
    {
        node_t *loc=Node;
        for(int i=0;word[i];i++)
        {
            int sn=word[i]-'0';
            if(!loc->son[sn]) loc->son[sn]=_NewNode();
            loc=loc->son[sn];
        }
        loc->idx=data;
    }
    inline int find(const char word[])
    {
        node_t *loc=Node;
        for(int i=0;word[i];i++)
        {
            int sn=word[i]-'0';
            if(!loc->son[sn]) return -1;
            loc=loc->son[sn];
        }
        return loc->idx;
    }
};
hashCode dp;
inline void to_status(char str[])
{
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            str[i*m+j]=chess[i][j];
    str[n*m]='\0';
}
int dfs()
{
    char str[MAXN*MAXN];
    to_status(str);
    int ret=dp.find(str);
    if(ret!=-1) return ret;
    bool sg[150];
    memset(sg,false,sizeof(sg));
    for(int i=0;i<n-1;i++)
        for(int j=0;j<m-1;j++)
            if(chess[i][j]=='0'&&chess[i][j+1]=='0'&&chess[i+1][j]=='0'&&chess[i+1][j+1]=='0')
            {
                chess[i][j]=chess[i][j+1]=chess[i+1][j]=chess[i+1][j+1]='1';
                int sign=dfs();
                sg[sign]=true;
                chess[i][j]=chess[i][j+1]=chess[i+1][j]=chess[i+1][j+1]='0';
            }
    while(true)
    {
        if(!sg[++ret])
        {
            dp.insert(str,ret);
            return ret;
        }
    }
}
int main()
{
    int t;
    while(scanf("%d",&t)!=EOF)
    {
        dp.init();
        int sign=0;
        for(int i=0;i<t;i++)
        {
            scanf("%d%d",&n,&m);
            for(int j=0;j<n;j++)
                scanf("%s",chess[j]);
            sign^=dfs();
        }
        puts(sign?"Yes":"No");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值