POJ 3322 Bloxorz I (bfs+辅助数组+状态压缩+自己的一些搜索理解)

来源:互联网 发布:网络视频直播软件 编辑:程序博客网 时间:2024/05/17 08:58

Description

Little Tom loves playing games. One day he downloads a little computer game called 'Bloxorz' which makes him excited. It's a game about rolling a box to a specific position on a special plane. Precisely, the plane, which is composed of several unit cells, is a rectangle shaped area. And the box, consisting of two perfectly aligned unit cube, may either lies down and occupies two neighbouring cells or stands up and occupies one single cell. One may move the box by picking one of the four edges of the box on the ground and rolling the box 90 degrees around that edge, which is counted as one move. There are three kinds of cells, rigid cells, easily broken cells and empty cells. A rigid cell can support full weight of the box, so it can be either one of the two cells that the box lies on or the cell that the box fully stands on. A easily broken cells can only support half the weight of the box, so it cannot be the only cell that the box stands on. An empty cell cannot support anything, so there cannot be any part of the box on that cell. The target of the game is to roll the box standing onto the only target cell on the plane with minimum moves.


The box stands on a single cell

The box lies on two neighbouring cells, horizontally

The box lies on two neighbouring cells, vertically

After Little Tom passes several stages of the game, he finds it much harder than he expected. So he turns to your help.

Input

Input contains multiple test cases. Each test case is one single stage of the game. It starts with two integersR andC(3 ≤ R, C ≤ 500) which stands for number of rows and columns of the plane. That follows the plane, which containsR lines andCcharacters for each line, with 'O' (Oh) for target cell, 'X' for initial position of the box, '.' for a rigid cell, '#' for a empty cell and 'E' for a easily broken cell. A test cases starts with two zeros ends the input.

It guarantees that

  • There's only one 'O' in a plane.
  • There's either one 'X' or neighbouring two 'X's in a plane.
  • The first(and last) row(and column) must be '#'(empty cell).
  • Cells covered by 'O' and 'X' are all rigid cells.

Output

For each test cases output one line with the minimum number of moves or "Impossible" (without quote) when there's no way to achieve the target cell.  

Sample Input

7 7########..X####..##O##....E##....E##.....########0 0

Sample Output

10
 
自己敲了一上午,思路和峰峰的差不多,但是没有程序结构化的经验,所以思路看起来也不怎么清晰
然后好像题目看漏了初始时可以有立着、横躺着、竖躺着三种状态了。。。
峰峰建辅助数组的做法真是太高端了。。。。(本菜鸟真是还没想出这种做法。。。嗯。。。以后可以借鉴)
我自己写的代码虽然很混乱,但还是想找时间改一下,再贴出来。。。。嗯,下面是我看了峰峰的代码后敲的。。。。先贴出来。。。
 
解题:这个状态------->(通过某种变换)------>下一个状态
     
     相应的确定数组的维度
     (注:sta[][]也是这么确定,当前状态------>(变换方向)--------->下一个状态)
 
代码:
//box占两格,所以用一个结构体表示横纵坐标分别为(x1,y1),//横纵坐标分别为(x1,y1),(x2,y2)//state表示状态//steps表示当前已走的步数//由于从一步到下一步的变换与当前的状态和翻转的方向有关//当前状态有0=立着,1=横躺着,2=竖躺着//翻转的方向有0=上,1=下,2=左,3=右//故开个二维的辅助数组表示坐标变换//dx1[3][4],dy1[3][4]。。。都为辅助数组//注意走过的地方和状态要标记,故vis[][][],前两维记录坐标//第三维记录走过时的状态#include<cstdio>#include<iostream>#include<cstring>using namespace std;struct node{    int x1;    int x2;    int y1;    int y2;    int state;    int steps;}start;             //start为起始位置node q[1000000];    //开成100000就runtime errorbool vis[510][510][3];char maps[510][510];int ddx[4]={-1,1,0,0};int ddy[4]={0,0,-1,1};int dx1[3][4]={{-2,1,0,0},{-1,1,0,0},{-1,2,0,0}};    int dy1[3][4]={{0,0,-2,1},{0,0,-1,2},{0,0,-1,1}};int dx2[3][4]={{-1,2,0,0},{-1,1,0,0},{-2,1,0,0}};int dy2[3][4]={{0,0,-1,2},{0,0,-2,1},{0,0,-1,1}};int st[3][4]={{2,2,1,1},{1,1,0,0},{0,0,2,2}};int r,c;int endx,endy;int inmaps(int x,int y)        //判断是否在给定的范围内{    return x>=0&&x<r&&y>=0&&y<c;}bool isok(node &t){    if(!inmaps(t.x1,t.y1)||!inmaps(t.x2,t.y2))        return false;    if(maps[t.x1][t.y1]=='#'||maps[t.x2][t.y2]=='#')        return false;    if(maps[t.x1][t.y1]=='E'&&t.state==0)        return false;    return true;}//将初始位置和状态记录下来//并将目的地的横纵坐标记录下来void create()      {    int i,j;    for(i=0;i<r;i++){        for(j=0;j<c;j++)        {            if(maps[i][j]=='O')            {                endx=i;                endy=j;            }            else if(maps[i][j]=='X')            {                start.x1=start.x2=i;                start.y1=start.y2=j;                int dx=i+ddx[1];                      int dy=j+ddy[1];                int rx=i+ddx[3];                int ry=j+ddy[3];                if(inmaps(rx,ry)&&maps[rx][ry]=='X')                {                    start.state=2;                    start.x2=rx;                    start.y2=ry;                    maps[rx][ry]=maps[i][j]='.';                }                else if(inmaps(dx,dy)&&maps[dx][dy]=='X')                {                    start.state=1;                    start.x2=dx;                    start.y2=dy;                    maps[dx][dy]=maps[i][j]='.';                }                else                {                    start.state=0;                    maps[i][j]='.';                }            }        }}    start.steps=0;}//为什么要建两个node结构体m、n呢//我的理解是:因为expand很巧妙的传了引用//如果不能扩展,就不入队,同时要想原来的节点不改变//就要用副本作为expand()函数的形参bool expand(node &t,int d){    t.x1+=dx1[t.state][d];    t.y1+=dy1[t.state][d];    t.x2+=dx2[t.state][d];    t.y2+=dy2[t.state][d];    t.state=st[t.state][d];    t.steps++;    if(!isok(t))        return false;    if(!vis[t.x1][t.y1][t.state])    {        vis[t.x1][t.y1][t.state]=1;        return true;    }return false;}void bfs(){    node m,n;    int front=0,rear=0;    q[rear++]=start;    while(front<rear)    {        m=q[front];        for(int i=0;i<4;i++)        {            n=m;            if(expand(n,i)){                q[rear++]=n;if(n.x1==endx&&n.y1==endy&&n.state==0){ printf("%d\n",n.steps); return;}}        }        front++;    }    printf("Impossible\n");}int main(){    while(~scanf("%d%d",&r,&c))    {        if(r==0&&c==0)            break;        for(int i=0;i<r;i++)            scanf("%s",maps[i]);        memset(vis,0,sizeof(vis));        create();        bfs();    }    return 0;}

 

	
				
		
原创粉丝点击