• 【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;
    }
    


  • 相关阅读:
    《算法导论》读书笔记之第16章 贪心算法—活动选择问题
    C语言综合实验1—学生信息管理系统
    《算法导论》读书笔记之第15章 动态规划[总结]
    《算法导论》读书笔记之第11章 散列表
    模板类中定义list<T>::iterator iter在g++下不识别的解决办法
    C语言参考程序—无符号一位整数的四则运算
    《算法导论》读书笔记之第15章 动态规划—最优二叉查找树
    C语言综合实验2—长整数运算
    递归与尾递归总结
    《算法导论》读书笔记之第13章 红黑树
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793895.html
Copyright © 2020-2023  润新知