题目大意:第一行输入2个整数n,m。分别表示棋盘的行数和列数。在接下来就是给出棋盘的情况(0 表示该位置可用 , 1 : 表示该位置不可用)。
解题思路:这道题,看别人推荐的时候是博弈累的题目。但是我当成是铺板砖类的题目来做了。就是用暴力的方法
必胜态:从当前状态所能到达的状态中存在一个必败态
必败态:从当前状态所能达到的状态全部是必胜态
本题状态:当前整个棋盘的状态
由题意确定的必败态:不能再放的为必败态
解决方法:对当前状态A(此时的整个棋盘),每个可以
方的位置放上一个,然后去判定此状态B是否必败,若
必败,那么当前状态A为必胜态。若所有的可以走到的
状态B都是必胜态,那么当前状态A为必败态。无路可走
的也肯定是必败态。递归结束便可得到结果,返回0必败
返回1必胜。
代码如下:
/*
* 1760_1.cpp
*
* Created on: 2013年9月2日
* Author: Administrator
*/
#include <iostream>
using namespace std;
const int maxn = 51;
bool g[maxn][maxn];
char s[maxn];
int n,m;
/**
* 拍那段当前位置是否可放
*/
bool set(int i, int j){
if(!g[i][j] && !g[i+1][j] && !g[i][j+1] && !g[i+1][j+1]){
g[i][j] = g[i+1][j] = g[i][j+1] = g[i+1][j+1] = true;
return true;
}
return false;
}
/**
* 恢复到原来状态
*/
void unset(int i , int j){
g[i][j] = g[i+1][j] = g[i][j+1] = g[i+1][j+1] = false;
}
bool dfs(){
int i,j;
for(i = 1 ; i < n ; ++i){//之所以不写成 i <= n 是因为这个正方形是2 * 2的。那样放会出界的
for(j = 1 ; j < m ; ++j){
if(set(i,j)){
if(!dfs()){
unset(i,j);
return true;//此位置放的话会导致一个必败态,故此状态必胜
}
unset(i,j);
}
}
}
return false;//没有找到必败态或无路可走了,故此状态必败
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
memset(g,0,sizeof(g));
int i,j;
getchar();
for(i = 1 ; i <= n ; ++i ){
gets(s);
for(j = 1 ; j <= m ; ++j){
g[i][j] = s[j - 1] == '1'?true:false;
}
}
printf("%s\n",dfs()?"Yes":"No");
}
}