HDU 1809 A New Tetris Game(2) 【SG函数】


传送门:HDU 1809



A New Tetris Game(2)
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Problem Description
自从Lele发明了新的类俄罗斯游戏 A New Tetris Game 后,他整日整夜得玩,现在渐渐的,他发现这个游戏也不过如此,为了加大点难度,他制定了一套新的规则:
首先,Lele和姐姐拿出N个长方形的棋盘,这些棋盘中有些格子是不可用的,剩下的都是可用的。每次Lele和姐姐轮流从N个棋盘里选出一个棋盘,拿出俄罗斯方块里的正方形方块(大小为2*2的正方形方块)往这个棋盘里放,要注意的是,放进去的正方形方块不能叠在棋盘不可用的格子上,也不能叠在已经放了的正方形方块上。
到最后,谁不能再放正方形方块,谁就输了。
现在,假设每次Lele和姐姐都很聪明,都能按最优策略放正方形,并且每次都是Lele先放正方形,你能告诉他他是否一定能赢姐姐吗?

Input
本题目包含多组测试,请处理到文件结束。
每组测试第一行包含一个正整数N(N<30),表示棋盘的输个数
接下来有N个棋盘的描述。
对于每个棋盘,第一行有两个整数R,C(R*C<50),分别表示棋盘的行数和列数。然后有R行,每行C个字符来表示这个棋盘。
其中0是代表棋盘该位置可用,1是代表棋盘该位置不可用
你可以假设,每个棋盘中,0的个数不会超过40个。

Output
对于每一组测试,如果Lele有把握获胜的话,在一行里面输出"Yes",否则输出"No"。

Sample Input
2
4 4
0000
0000
0000
0000
4 4
0000
0010
0100
0000
1
4 4
0000
0010
0100
0000

Sample Output
Yes
No



套用SG函数(dfs)模板,将二维数组转化为一维作为状态保存。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<map>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N=55;
int n,r,c;
char mp[N][N];
string s;
map<string,int> vis;
map<string,int> sg;
string add()//将二维变成一维记录状态
{
  s="";
  for(int i=0;i<r;i++)
  {
      s+=mp[i];
      s+='*';
  }
  return s;
}
int mex()
{
  string ss=add();
  if(vis[ss]) return sg[ss];
  int v[100];
  memset(v,0,sizeof(v));
  for(int i=0;i<r-1;i++)
  {
    for(int j=0;j<c-1;j++)
    {
      if(mp[i][j]=='0'&&mp[i][j+1]=='0'&&mp[i+1][j]=='0'&&mp[i+1][j+1]=='0')
      {
        mp[i][j]=mp[i][j+1]=mp[i+1][j]=mp[i+1][j+1]='1';
        v[mex()]=1;
        mp[i][j]=mp[i][j+1]=mp[i+1][j]=mp[i+1][j+1]='0';
      }
    }
  }
  int k=0;
  while(v[k]) k++;
  vis[ss]=1;
  sg[ss]=k;
  return k;
}
int main()
{
  while(scanf("%d",&n)!=EOF)
  {
    int ans=0;
    while(n--)
    {
      scanf("%d%d",&r,&c);
      for(int i=0;i<r;i++)
      {
        scanf("%s",mp[i]);
      }
      ans^=mex();
    }
    if(ans) printf("Yes\n");
    else printf("No\n");
  }
  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值