zoukankan      html  css  js  c++  java
  • 推箱子

    推箱子

    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;
    }
  • 相关阅读:
    MySQL实现了四种通信协议
    深入了解Windows句柄到底是什么
    Linux虚拟地址空间布局以及进程栈和线程栈总结
    malloc 函数详解
    数组指针和指针数组的区别
    Linux中sudo配置
    ctrl+c,ctrl+d,ctrl+z在linux程序中意义和区别
    linux select函数详解
    linux grep命令详解
    Linux find 用法示例
  • 原文地址:https://www.cnblogs.com/wuwangchuxin0924/p/6396169.html
Copyright © 2011-2022 走看看