【POJ1475】Pushing Boxes-A*(或BFS?)

测试地址:Pushing Boxes

题目大意:给定一个r*c的矩形地图,里面有一些石头,有石头的地方不能走,你一开始在S点,要将地图中的一个箱子B推到目标点T(玩过推箱子小游戏的同学应该很容易理解,没玩过的话我在这里解释一下,就是当你要往一个方向移动时,箱子正好在你要到达的地方,此时你和你的箱子都要往那个方向移动一步),箱子也不能被推到有石头的地方,求出一个表示路线的字符串,其中小写字母表示普通的移动,大写字母表示推着箱子时的移动,字母表示方向,要求推箱子的次数最少,如果有多解,输出总移动次数最少的,如果还是有多解,任意输出一个。如果不可能推到,输出“Impossible.”。

做法:这道题目看上去比较复杂,我们来梳理一下。首先要确定搜索时要记录的状态,这个很容易能想到:人的位置和箱子的位置。由于题目中要求的最优解,我们还要附加两个值pushes和walk,表示推动箱子的移动数和平常的移动数,pushes优先级比walk高,然后和前面已经搜出的状态做双关键字比较,如果比以前的状态好,就可以加入优先队列中,优先队列的排序规则也是这个规则。输出路线的话,只要记录一个状态的“父节点”,即拓展到该节点并使该节点状态最优的点,如果箱子的位置到达了T,就从这个状态开始反着搜,判断行走的方向即可。怎么判断是否推动了箱子?只要查看箱子的坐标是否移动即可。还有一个地方坑了我一把,就是存储路线的字符数组一定要开大,因为一个点不一定只走一遍或两遍,所以无法轻易判断路线的长度,所以内存足够的情况下,只能开大一点保险。

(这道题的确是好题...学习A*的同学一定要做一做)

(听说还有双BFS的方法?有待学习)

以下是本人代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
int r,c,move[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int fa[30][30][30][30][4],h[30][30][30][30][2],t=0;
char a[30][30];
bool flag;
struct node {int x,y;} S,B,T;

struct state
{
  node s,b;
  int pushes,walk;
  bool operator < (state a) const
  {
    if (pushes!=a.pushes) return a.pushes<pushes;
	else return a.walk<walk;
  }
};

void setbest(state p)
{
  h[p.s.x][p.s.y][p.b.x][p.b.y][0]=p.pushes;
  h[p.s.x][p.s.y][p.b.x][p.b.y][1]=p.walk;
}

bool best(state p)
{
  if (h[p.s.x][p.s.y][p.b.x][p.b.y][0]!=p.pushes) return p.pushes<h[p.s.x][p.s.y][p.b.x][p.b.y][0];
  else return p.walk<h[p.s.x][p.s.y][p.b.x][p.b.y][1];
}

bool can(int x,int y)
{
  return x>=1&&x<=r&&y>=1&&y<=c&&a[x][y]!='#';
}

void outputpath(int sx,int sy,int g)
{
  char r[10000];
  flag=1;
  int x1=sx,y1=sy,x2=T.x,y2=T.y,j=g;
  while(j>0)
  {
    int fx1,fx2,fy1,fy2;
	char tmp='a';
	fx1=fa[x1][y1][x2][y2][0];fy1=fa[x1][y1][x2][y2][1];
	fx2=fa[x1][y1][x2][y2][2];fy2=fa[x1][y1][x2][y2][3];
	if (fx2!=x2||fy2!=y2) tmp='A';
	if (x1-fx1==-1) r[j]='N'-'A'+tmp;
	if (x1-fx1==1) r[j]='S'-'A'+tmp;
	if (y1-fy1==-1) r[j]='W'-'A'+tmp;
	if (y1-fy1==1) r[j]='E'-'A'+tmp;
	j--;x1=fx1,y1=fy1,x2=fx2,y2=fy2;
  }
  for(int i=1;i<=g;i++)
    printf("%c",r[i]);
}

void AStar()
{
  memset(fa,0,sizeof(fa));
  memset(h,0x7f,sizeof(h));
  priority_queue<state> Q;
  state now,next;
  now.s=S,now.b=B;now.pushes=now.walk=0;
  Q.push(now);
  while(!Q.empty())
  {
    now=Q.top();
	Q.pop();
	if (now.b.x==T.x&&now.b.y==T.y) {outputpath(now.s.x,now.s.y,now.pushes+now.walk);break;}
	for(int i=0;i<=3;i++)
	  if (can(now.s.x+move[i][0],now.s.y+move[i][1]))
	  {
	    next.s.x=now.s.x+move[i][0];
		next.s.y=now.s.y+move[i][1];
	    if (now.b.x==now.s.x+move[i][0]&&now.b.y==now.s.y+move[i][1])
		{
		  if (!can(now.b.x+move[i][0],now.b.y+move[i][1])) continue;
		  next.b.x=now.b.x+move[i][0];
		  next.b.y=now.b.y+move[i][1];
		  next.pushes=now.pushes+1;next.walk=now.walk;
		}
		else
		{
		  next.b.x=now.b.x;
		  next.b.y=now.b.y;
		  next.walk=now.walk+1;next.pushes=now.pushes;
		}
		if (best(next))
		{
		  fa[next.s.x][next.s.y][next.b.x][next.b.y][0]=now.s.x;
		  fa[next.s.x][next.s.y][next.b.x][next.b.y][1]=now.s.y;
		  fa[next.s.x][next.s.y][next.b.x][next.b.y][2]=now.b.x;
		  fa[next.s.x][next.s.y][next.b.x][next.b.y][3]=now.b.y;
		  setbest(next);
		  Q.push(next);
		}
	  }
  }
}

int main()
{
  while(scanf("%d%d",&r,&c)&&r&&c)
  {
    t++;
    for(int i=1;i<=r;i++)
	{
	  char s[30];
	  scanf("%s",s);
	  for(int j=1;j<=c;j++)
	  {
	    a[i][j]=s[j-1];
	    if (s[j-1]=='S') S.x=i,S.y=j;
		if (s[j-1]=='B') B.x=i,B.y=j;
		if (s[j-1]=='T') T.x=i,T.y=j;
	  }
	}
	
	printf("Maze #%d
",t);
	flag=0;
	AStar();
	if (!flag) printf("Impossible.");
	printf("

");
  }
  
  return 0;
}


原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793893.html