您的位置:首页 > 其它

poj 2308 Dearboy's Puzzle 连连看

2015-08-03 23:37 232 查看
Dearboy's Puzzle

Time Limit: 1000MSMemory Limit: 65536K
Total Submissions: 1258Accepted: 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.
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.
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: