推箱子

推箱子

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\n",flag);
    }
    return 0;
}

 

posted @ 2017-02-14 09:15  勿忘初心0924  阅读(548)  评论(0编辑  收藏  举报