Dearboy's Puzzle
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 1258 | Accepted: 223 |
Description
Dearboy is a game lover. Recently, he loves playing the game Lian Lian Kan. This game is played on a board with N*M grids, and lots of cards are put on the board in the grids. You should find a pair of the same cards, if not more than three segments can link this pair without passing any other cards, you can take this pair away from the board. (You may be puzzled about the meaning of not more than 3 segments, just refer to the figure below, in which we express some allowable links). Continue the process above, if you can clear all the cards, you win the game, otherwise you lose it.
If you have played this game, you may know that sometimes the game has no solution and you are sure to lose. Dearboy is very boring about the games without solutions, so he asks you, a famous programmer, to tell him whether he can win the giving game phase or not.

If you have played this game, you may know that sometimes the game has no solution and you are sure to lose. Dearboy is very boring about the games without solutions, so he asks you, a famous programmer, to tell him whether he can win the giving game phase or not.
Input
The input consists of multiple test cases. The first line of each test case contains two integers N and M (2 <= N, M <= 10), which denote the sizes of the game board. The next N lines give the board layout, with each line containing M characters. A character is one of the following: ‘*’ (an empty position), ‘A’, ‘B’, ‘C’, ’D’ (the cards, which imply that there are at most 4 different kinds of cards). Different letters represent different cards. The number of same cards may be odd, and there may be more than one pair of the same cards.
The input is terminated with two 0's. This test case shoud not be processed.
The input is terminated with two 0's. This test case shoud not be processed.
Output
For each test case, print in one line "yes" if Dearboy can win the game, "no" otherwise.
Sample Input
6 8 ******** *A**C*** **B***** ***B*D** ****D*** ******** 2 2 AB BA 6 8 ***A**** *A**C*** **B***C* ***B*D** ****D*** ******** 0 0
Sample Output
no no yes
Source
POJ Monthly,Wang Yijie
通过这个题,加深了对dfs和bfs的认识 ,dfs的特点在于回溯,不一定只限于走迷宫、选或不选、选下一个,
其结束的方式根据题目的不同有所变化,稍微做出变化可以应对不同的情况。
此题先用dfs,然后在dfs中再用dfs或bfs,
先用dfs是在整张图上试,看看消掉哪些对会怎样,具体的实现方法是先找到一个还没被消掉的点,然后从这个点出发,dfs或bfs找到与之成对的点。然后消掉他们,不断尝试,不断回溯,找到即可退出dfs。
底下有个重要的剪枝:
即图中某一部分出现底下这种情况且A、B都只剩下两个,最终不能消掉。
AB
BA
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<climits>
#include<queue>
#include<vector>
#include<map>
#include<sstream>
#include<set>
#include<stack>
#include<utility>
//#pragma comment(linker, "/STACK:102400000,102400000")
#define PI 3.1415926535897932384626
#define eps 1e-10
#define sqr(x) ((x)*(x))
#define FOR0(i,n) for(int i=0 ;i<(n) ;i++)
#define FOR1(i,n) for(int i=1 ;i<=(n) ;i++)
#define FORD(i,n) for(int i=(n) ;i>=0 ;i--)
#define lson num<<1,le,mid
#define rson num<<1|1,mid+1,ri
#define MID int mid=(le+ri)>>1
#define zero(x)((x>0? x:-x)<1e-15)
using namespace std;
const int INF =0x3f3f3f3f;
const int maxn= 10 ;
const int maxm= 10 ;
//const int INF= ;
//typedef long long ll;
//ifstream fin("input.txt");
//ofstream fout("output.txt");
//fin.close();
//fout.close();
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int a[maxn+4][maxm+4];
bool vis[maxn+2][maxm+2];
int num[6];
bool ok;
int n,m;
int dir[4][2]={ {-1,0},{+1,0},{0,-1},{0,+1} };
struct Node
{
int y,x;
int turn,dir;
Node(){}
Node( int yy,int xx,int tur,int d ):y(yy),x(xx),turn(tur),dir(d) {}
//dir代表方向,turn代表转弯次数
} ;
bool in(Node &c)
{
return 1<=c.y&&c.y<=n&&1<=c.x&&c.x<=m;
}
bool in(int &y,int &x)
{
return 1<=y&&y<=n&&1<=x&&x<=m;
}
bool in(int y,int x)
{
return 1<=y&&y<=n&&1<=x&&x<=m;
}
void bfs(int y,int x,int prin,int s[42][2],int& cct)
{
queue<Node> q;
Node st( y,x,0 ,-1);
q.push(st);
memset(vis,0,sizeof vis);
vis[y][x]=1;
while(!q.empty())
{
Node st=q.front();q.pop();
for(int i=0;i<4;i++)
{
int ty=st.y+dir[i][0];
int tx=st.x+dir[i][1];
Node now(ty,tx,st.turn,i);
if(!in(now) || vis[ty][tx] ) continue;
if(a[ty][tx]!=prin &&a[ty][tx]!=0 ) continue;
if(i!=st.dir&& st.dir!=-1 ) now.turn+=1;
if(now.turn>2) continue;
vis[ty][tx]=1;
if(a[ty][tx]==prin)
{
s[cct][0]=ty;
s[cct++][1]=tx;
continue;
}
q.push(now );
}
}
}
bool cant()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(!in( i+1,j+1) ) continue;
if( !a[i][j] ||!a[i][j+1] ) continue;
if(a[i][j]==a[i+1][j+1] && a[i][j+1]==a[i+1][j] && num[a[i][j]]==2&& num[a[i][j+1]]==2)
return true;
}
}
return false;
}
void dfs(int cnt)
{
if(ok) return;
if(cnt==0) {ok=1;return;}
if(cant()) return; //这个剪枝很重要
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(ok) return;
if(!a[i][j]) continue;
int s[42][2];int cct=0;
int stcolor=a[i][j];
bfs( i,j, stcolor, s, cct );
a[i][j]=0;
num[ stcolor ]-=2;
for(int k=0;k<cct;k++)
{
int y=s[k][0];
int x=s[k][1];
int nowcolor=a[y][x];
a[y][x]=0;
// if(cnt==2) {ok=1;return;}
dfs(cnt-2);
a[y][x]=nowcolor;
}
num[stcolor]+=2;
a[i][j]=stcolor;
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m)&&(n||m))
{
char c;
int cnt=0;
memset(num,0,sizeof num);
FOR1(i,n)
FOR1(j,m)
{
scanf(" %c",&c);
if(c=='*') num[0]++,a[i][j]=0;
else if(c=='A') num[1]++,a[i][j]=1,cnt++;
else if(c=='B') num[2]++,a[i][j]=2,cnt++;
else if(c=='C') num[3]++,a[i][j]=3,cnt++;
else num[4]++,a[i][j]=4,cnt++;
}
if( num[1]%2 ||num[2]%2 ||num[3]%2 ||num[4]%2 )
{
puts("no");continue;
}
ok=0;
dfs(cnt);
puts(ok?"yes":"no") ;
}
return 0;
}