1457.推箱子

Time Limit: 3000 MS         Memory Limit: 65536 K
Total Submissions: 58 (15 users)         Accepted: 24 (10 users)
[ My Solution ]

Description

推箱子是个家喻户晓的游戏相信在大家小的时候都一定玩过。当然我们在这里还是做个简单介绍如下图所示游戏玩家初始站在地图的某个位置游戏目标是将图中的箱子全部移往目的地(下图’X’的位置), 每次移动只能选择上下左右方向上某个方向移动一格若移动的方向上有箱子存在则箱子也往相同的方向移动一格并且在移动过程中玩家(和箱子)不能穿越(或停留于)箱子、障碍物(下图树的位置)和边界区域的位置。除此之外为了尽可能的得到最高分玩家还应该以尽可能少的步数完成任务。

 

为了简化问题现在给你一个地图,  且地图上的游戏者、箱子和目的地都各只有一个, 你需要求出最少需要多少步才能完成任务呢?

Input

输入的第一行有2个整数n, m (2 <= n, m <= 30), 接下来有n行, 每行有m个只由'.' , '*' , 'P', 'B', 'E' 构成的字符, 其中, ‘.’表示可通行区域, '*' 表示障碍物, 'P'表示玩家, 'B'表示箱子, 'E'表示目的地, 输入保证字符'P', 'B', 'E'各只有一个。

Output

若无法完成任务, 则输出-1, 否则输出的第一行有一个数字n, 表示将箱子移至目的地的最少步数, 第二行有n个字符, 表示玩家的移动步骤, 其中'L'表示左移, 'R'表示右移, 'U'表示上移, 'D'表示下移。(若存在多种满足题意的方案, 则任意一组答案都可以通过本题)

Sample Input

6 7
...*...
.*.*.*.
.*...*.
.*.**..
.****B*
.....EP

Sample Output

26
LLLLLLUUUUURRDDRRUURRDDDLD

Hint

这是一道SPECIAL JUDGE的题目, 每组数据, 时限1s

Source

doraemon @ xmu

 

 

 

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;

#define N 35

int n,m,op[4][2]={1,0,0,1,-1,0,0,-1};
char mat[N][N],path[1000000],mp[3][3];
struct node
{
 int x,y;
}p,e,b;

int vis[N][N][N][N],dp[N][N][N][N];
struct point
{
 int x1,y1,x2,y2;
 point(){}
 point(int a,int b,int c,int d):x1(a),y1(b),x2(c),y2(d){}
}pa[N][N][N][N];

int bfs()
{
 int i,ans,x,y,tag;
 node temp,u,B,temB;
 memset(vis,0,sizeof(vis));
 memset(dp,63,sizeof(dp));
 vis[p.x][p.y][b.x][b.y]=1;
 tag=dp[p.x][p.y][b.x][b.y];
 dp[p.x][p.y][b.x][b.y]=0;
 queue <node > que,box;
 que.push(p);box.push(b);
 while(!que.empty())
 {
  u=que.front();que.pop();
  B=box.front();box.pop();
  for(i=0;i<4;i++)
  {
   temp=u;temB=B;
   temp.x+=op[i][0];
   temp.y+=op[i][1];
   if(temp.x<1||temp.x>n||temp.y<1||temp.y>m||mat[temp.x][temp.y]=='*') continue;
   if(temp.x==B.x&&temp.y==B.y)
   {
    temB.x+=op[i][0];
    temB.y+=op[i][1];
    if(temB.x<1||temB.x>n||temB.y<1||temB.y>m||mat[temB.x][temB.y]=='*') continue;
   }
   if(dp[u.x][u.y][B.x][B.y]+1<dp[temp.x][temp.y][temB.x][temB.y])
   {
    pa[temp.x][temp.y][temB.x][temB.y]=point(u.x,u.y,B.x,B.y);
    dp[temp.x][temp.y][temB.x][temB.y]=dp[u.x][u.y][B.x][B.y]+1;
    if(!vis[temp.x][temp.y][temB.x][temB.y])
    {
     vis[temp.x][temp.y][temB.x][temB.y]=1;
     que.push(temp);box.push(temB);
    }
    if(temB.x==e.x&&temB.y==e.y) break;
   }
  }
  if(temB.x==e.x&&temB.y==e.y) break;
  vis[u.x][u.y][B.x][B.y]=0;
 }
 point end;
 ans=tag;
 for(i=0;i<4;i++)
 {
  temp=e;
  temp.x+=op[i][0];
  temp.y+=op[i][1];
  if(temp.x<1||temp.x>n||temp.y<1||temp.y>m||mat[temp.x][temp.y]=='*') continue;
  if(dp[temp.x][temp.y][e.x][e.y]<ans)
  {
   ans=dp[temp.x][temp.y][e.x][e.y];
   end=point(temp.x,temp.y,e.x,e.y);
  }
 }
 if(ans==tag)
  return -1;
 i=0;
 while(end.x1!=p.x||end.y1!=p.y||end.x2!=b.x||end.y2!=b.y){
  x=end.x1-pa[end.x1][end.y1][end.x2][end.y2].x1;
  y=end.y1-pa[end.x1][end.y1][end.x2][end.y2].y1;
  path[i++]=mp[x+1][y+1];
  end=pa[end.x1][end.y1][end.x2][end.y2];
 }
 x=i;
 path[i]=0;
 for(i=0;i<x/2;i++) swap(path[i],path[x-i-1]);
 return ans;
}

int main()
{
 int i,j,ans;
 mp[2][1]='D';mp[1][2]='R';
 mp[0][1]='U';mp[1][0]='L';
 while(scanf("%d%d",&n,&m)!=EOF)
 {
  for(i=1;i<=n;i++)
   scanf("%s",mat[i]+1);
  for(i=1;i<=n;i++)
  {
   for(j=1;j<=m;j++)
   {
    if(mat[i][j]=='P')
    {
     p.x=i;p.y=j;
    }
    if(mat[i][j]=='E')
    {
     e.x=i;e.y=j;
    }
    if(mat[i][j]=='B')
    {
     b.x=i;b.y=j;
    }
   }
  }
  ans=bfs();
  if(ans!=-1) printf("%d\n%s\n",ans,path);
  else printf("-1\n");
 }
 return 0;
}

/*
5 4
*...
*...
*...
.*BE
.P..

*/

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值