推箱子 |
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) |
Total Submission(s): 116 Accepted Submission(s): 58 |
Problem Description
推箱子是一个很经典的游戏.今天我们来玩一个简单版本.在一个M*N的房间里有一个箱子和一个搬运工,搬运工的工作就是把箱子推到指定的位置,注意,搬运工只能推箱子而不能拉箱子,因此如果箱子被推到一个角上(如图2)那么箱子就不能再被移动了,如果箱子被推到一面墙上,那么箱子只能沿着墙移动.
现在给定房间的结构,箱子的位置,搬运工的位置和箱子要被推去的位置,请你计算出搬运工至少要推动箱子多少格. |
Input
输入数据的第一行是一个整数T(1<=T<=20),代表测试数据的数量.然后是T组测试数据,每组测试数据的第一行是两个正整数M,N(2<=M,N<=7),代表房间的大小,然后是一个M行N列的矩阵,代表房间的布局,其中0代表空的地板,1代表墙,2代表箱子的起始位置,3代表箱子要被推去的位置,4代表搬运工的起始位置.
|
Output
对于每组测试数据,输出搬运工最少需要推动箱子多少格才能帮箱子推到指定位置,如果不能推到指定位置则输出-1.
|
Sample Input
1 5 5 0 3 0 0 0 1 0 1 4 0 0 0 1 0 0 1 0 2 0 0 0 0 0 0 0 |
Sample Output
4 |
Author
Ignatius.L & weigang Lee
|
Recommend
Ignatius.L
|
/* 题意:略 初步思路:简单的bfs()只不过是反向的,每次想要移动箱子的时候必须要看看反方向有没有障碍物,其次用dfs()判断人 是不是能到达相应的位置 #错误:卧槽,写完了立马出结果了,把我这个激动啊,立马交上了,结果马上给我一个WA,伤死了 找了一组让我死的数据 5 5 0 4 0 0 0 1 2 1 0 0 3 0 0 1 0 1 0 0 1 0 1 0 0 1 0 还有一个问题,就是bfs()的时候不能标记箱子的位置,因为上面这组数据箱子肯定是要走两次(2,1)这个位置的 dfs()写错了,判断的不对 #超时:靠!dfs()换成bfs()试试,不是这个问题,是推箱子的时候,箱子的位置也要标记,不能单纯的记录坐标,还要有方向 #感悟:昨天下午四点,写道现在九点半了,睡觉去了 Zzzzz */ #include<bits/stdc++.h> using namespace std; struct Point{//单纯的坐标结构体 int x,y; Point(){} Point(int a,int b){ x=a; y=b; } }; struct node{ Point Case,People;//箱子的位置,此刻人的位置 int step; node(){} node(Point a,Point b,int c){ Case=a; People=b; step=c; } }; int t,n,m; node start;//初始位置 Point finnal_x;//箱子的末位置 int mapn[10][10];//地图 int vis_p[10][10];//标记人是否走过了 int vis[10][10][5];//标记箱子是否走过,和从什么方向来的 int dir[4][2]={1,0,0,1,0,-1,-1,0};//上,右,左,下 bool ok_p(Point a){//判断人是不是在合法的位置 if(a.x<0||a.x>=n||a.y<0||a.y>=m||mapn[a.x][a.y]==1||vis_p[a.x][a.y]) //不能越界,不能在此刻箱子的位置,这地方走过了 return false; return true; } bool judge(Point a,Point b){//判断人是否能到达相应的位置,从a到b queue<Point>q; q.push(a); while(!q.empty()){ a=q.front(); q.pop(); if(a.x==b.x&&a.y==b.y) return true; for(int i=0;i<4;i++){ Point Next=a; Next.x+=dir[i][0]; Next.y+=dir[i][1]; if(ok_p(Next)==false) continue; vis_p[Next.x][Next.y]=1; q.push(Next); } } return false; } bool ok(Point a){//判断箱子是不是在合法的位置 if(a.x<0||a.x>=n||a.y<0||a.y>=m|| mapn[a.x][a.y]==1) //不能越界,除此之外只要不是墙就行,#还有这地方不能走过了#这里错了,能重复走 return false; return true; } int bfs(){ memset(vis,0,sizeof vis); queue<node>q; start.step=0; Point Next,Next_p; q.push(start);//放进去初位置 while(!q.empty()){ start=q.front(); q.pop(); // cout<<start.Case.x<<" "<<start.Case.y<<" "<<start.People.x<<" "<<start.People.y<<" "<<start.step<<endl; if(start.Case.x==finnal_x.x&&start.Case.y==finnal_x.y)//找到箱子了 return start.step; for(int i=0;i<4;i++){ //判断人是不是能到达箱子移动的反方向 Next_p=start.People;//箱子还没移动之前的人的位置 memset(vis_p,0,sizeof vis_p); vis_p[start.Case.x][start.Case.y]=1;//首先还没用之前箱子的位置是不能去的 vis_p[Next_p.x][Next_p.y]=1;//其次将人的首位置标记 // cout<<"+----------------------+"<<endl; // cout<<"人 的位置:"<<Next_p.x<<" "<<Next_p.y<<endl; // cout<<"箱子的位置:"<<start.Case.x<<" "<<start.Case.y<<endl; // cout<<"到达的位置:"<<start.Case.x-dir[i][0]<<" "<<start.Case.y-dir[i][1]<<endl; // cout<<judge( Next_p,Point(start.Case.x-dir[i][0],start.Case.y-dir[i][1]) )<<endl; // cout<<"+----------------------+"<<endl; // if(Next_p.x==2&&Next_p.y==1&&start.Case.x-dir[i][0]==4&&start.Case.y-dir[i][1]==1){ // cout<<endl; // cout<<"箱子的位置:"<<start.Case.x<<" "<<start.Case.y<<endl; // cout<<judge( Next_p,Point(start.Case.x-dir[i][0],start.Case.y-dir[i][1]) )<<endl; // for(int k=0;k<n;k++){ // for(int j=0;j<m;j++){ // cout<<vis_p[k][j]<<" "; // } // cout<<endl; // } // cout<<endl; // cout<<"箱子接下来的位置:"<<start.Case.x+dir[i][0]<<" "<<start.Case.y+dir[i][1]<<endl; // } if(judge( Next_p,Point(start.Case.x-dir[i][0],start.Case.y-dir[i][1]) )==false) //人到不了反方向 continue; //判断箱子是不是合法 Next.x=start.Case.x+dir[i][0]; Next.y=start.Case.y+dir[i][1]; // if(Next_p.x==2&&Next_p.y==1&&start.Case.x-dir[i][0]==4&&start.Case.y-dir[i][1]==1){ // cout<<Next.x<<" "<<Next.y<<" "<<start.Case.x<<" "<<start.Case.y<<endl; // } if(vis[Next.x][Next.y][i]||ok(Next)==false)//箱子的位置不合法 continue; //推完之后,人到了之前箱子的位置 vis[Next.x][Next.y][i]=1; q.push( node(Next,start.Case,start.step+1) ); } } return -1; } int main(){ // freopen("in.txt","r",stdin); scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ scanf("%d",&mapn[i][j]); if(mapn[i][j]==4){ start.People.x=i; start.People.y=j; mapn[i][j]=0; } if(mapn[i][j]==3){ finnal_x.x=i; finnal_x.y=j; mapn[i][j]=0; } if(mapn[i][j]==2){ start.Case.x=i; start.Case.y=j; mapn[i][j]=0; } } }//输入地图 int flag=bfs(); printf("%d ",flag); } return 0; }