推箱子

推箱子

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

 

转载于:https://www.cnblogs.com/wuwangchuxin0924/p/6396169.html

´问题描述: 码头仓库是划分为n×m个格子的矩形阵列。有公共边的格子是相邻格子。当前仓库中 有的格子是空闲的;有的格子则已经堆放了沉重的货物。由于堆放的货物很重,单凭仓库管 理员的力量是无法移动的。仓库管理员有一项任务,要将一个小箱子推到指定的格子上去。 管理员可以在仓库中移动,但不能跨过已经堆放了货物的格子。管理员站在与箱子相对的空 闲格子上时,可以做一次推动,把箱子推到另一相邻的空闲格子。推箱时只能向管理员的对 面方向推。由于要推动的箱子很重,仓库管理员想尽量减少推箱子的次数。 ´编程任务: 对于给定的仓库布局,以及仓库管理员在仓库中的位置箱子的开始位置目标位置, 设计一个解推箱子问题的分支限界法, 计算出仓库管理员将箱子从开始位置推到目标位置所 需的最少推动次数。 ´数据输入: 由文件input.txt提供输入数据。输入文件第 1 行有 2个正整数 n m(1<=n,m<=100) , 表示仓库是n×m个格子的矩形阵列。接下来有 n行,每行有 m个字符,表示格子的状态。 S 表示格子上放了不可移动的沉重货物; w 表示格子空闲; M 表示仓库管理员的初始位置; P 表示箱子的初始位置; K 表示箱子的目标位置。 ´结果输出: 将计算出的最少推动次数输出到文件 output.txt。如果仓库管理员无法将箱子从开始位 置推到目标位置则输出“No solution!” 。 输入文件示例 输出文件示例 input.txt output.txt
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值