[模拟训练]箱子

题目描述 箱子

【问题描述】

有个桌子长 R 宽 C,被分为 R*C 个小方格。其中,一些方格上有箱子,一些方格上有 按 钮,一些方格上有障碍物,一些方格上是空地。现在有个任务,需要把所有箱子推到这 些按 钮上面。箱子有个特征,只能推不能搬不能拉。现在需要用最少的步数把所有箱子推 到按钮 上。 当然,箱子和人都只能以格子为单位移动,不存在一部分在格内一部分在格外 的情况; 只能向四个方向推,箱子和推箱子的队员都不能穿越障碍物。推动的定义是,人 的前进方向 被箱子挡住,且箱子在顺着前进方向的下一格不是箱子或者障碍物,那么就可 以推着箱子和 箱子一起前进一步。

【输入文件】

输入第一行有两个整数 R,C(4<=R,C<=7),代表桌子的长和宽,接下来一共有 R 行, 每行有 C 个字符。
字符的含义:
0:代表空地
1:代表障碍物
2:代表箱子
3:代表按钮
4:人所在的初始地方
输入数据保证障碍物环绕整个地图,箱子数目跟按钮数目相同,箱子最少有一个,不会超过 3 个,队员肯定只有一个。不用考虑箱子初始就按着按钮的情况。保证有解。

【输出文件】

输出只有一行,为解决机关的最小步数。

【输入样例】

4 5
11111
14231
10231
11111

【输出样例】

4

【样例说明】

在样例中,最快的方法之一是先向东把第一个箱子推到按钮上,然后向西走 回原处,之 后向南一步,再向东推第二个箱子到按钮上。至此任务完成,共使用了 4 步。

【数据范围】

对 30%的输入数据 :箱子只有一个。
对 100%的输入数据 :4<=R,C<=7。


分析

用 dist[position][box1][box2][box3]记录人在 position,箱子 1 在 box1,箱子 2 在 box2,箱子 3 在 box3 位置时最少需要花费的步数。Bfs 一遍即可。


对于地图类、网格类题目,一般要定义多维状态来记录地图上的每个需要记录的状态,以方便将上一步的信息转移到下一步。可对每个网格进行拉通标号以节省维度((n-1)*m+j)。

#include<bits/stdc++.h>
using namespace std;
int f[50][50][50][50],pos[7][7],c[6000001][4];
int D[5][3],len,a[4],tot,v[4],R[64][3],n,m,A[8][8];
bool b[9][9];
char s1[9];
int main(){
//  freopen("box.in","r",stdin);
//  freopen("box.out","w",stdout);
    scanf("%d%d",&n,&m);
    int Sx,Sy;
    D[1][1]=1;D[1][2]=0;
    D[2][1]=-1;D[2][2]=0;
    D[3][1]=0;D[3][2]=1;
    D[4][1]=0;D[4][2]=-1;
    len=0;tot=0;
    int cnt=0;
    memset(R,0,sizeof(R));
    memset(a,0,sizeof(a));
    memset(v,0,sizeof(v));
    for (int i=1; i<=n; i++){
        scanf("%s",s1);
        for (int j=1; j<=m; j++){
            pos[i][j]=++cnt;
            R[cnt][1]=i;
            R[cnt][2]=j;
            A[i][j]=s1[j-1]-'0';
            if (A[i][j]==4) Sx=i,Sy=j,A[i][j]=0;
            if (A[i][j]==2) a[++len]=pos[i][j];
            if (A[i][j]==3) v[++tot]=pos[i][j];
        }
    }
    memset(f,255,sizeof(f));
    f[pos[Sx][Sy]][a[1]][a[2]][a[3]]=0;
    c[1][0]=pos[Sx][Sy];
    c[1][1]=a[1];
    c[1][2]=a[2];
    c[1][3]=a[3];
    memset(b,true,sizeof(b));
    for (int i=1; i<=n; i++)
        for (int j=1; j<=m; j++)
            if (A[i][j]==1) b[i][j]=false;
    for (int k=1,l=1; l<=k; l++) {
        int ren=c[l][0],xiang1=c[l][1],xiang2=c[l][2],xiang3=c[l][3],
            xren=R[ren][1],yren=R[ren][2],
            x1=R[xiang1][1],y1=R[xiang1][2],
            x2=R[xiang2][1],y2=R[xiang2][2],
            x3=R[xiang3][1],y3=R[xiang3][2];
        b[x1][y1]=false;
        b[x2][y2]=false;
        b[x3][y3]=false;
        int sx=f[ren][xiang1][xiang2][xiang3];
        if (xiang1==v[1] && xiang2==v[2] && xiang3==v[3]) {
            printf("%d\n",f[ren][xiang1][xiang2][xiang3]);
            return 0;
        }
        for (int i=1; i<=4; i++)
            if (1<=xren+D[i][1] && xren+D[i][1]<=n && 1<=yren+D[i][2] && yren+D[i][2]<=m) {
                if (b[xren+D[i][1]][yren+D[i][2]]
                        && f[pos[xren+D[i][1]][yren+D[i][2]]][xiang1][xiang2][xiang3]==-1) {
                    f[pos[xren+D[i][1]][yren+D[i][2]]][xiang1][xiang2][xiang3]=sx+1;
                    c[++k][0]=pos[xren+D[i][1]][yren+D[i][2]];
                    c[k][1]=xiang1;
                    c[k][2]=xiang2;
                    c[k][3]=xiang3;
                }
                int Q[4];
                Q[1]=xiang1;
                Q[2]=xiang2;
                Q[3]=xiang3;
                if (pos[xren+D[i][1]][yren+D[i][2]]==Q[2]) swap(Q[1],Q[2]);
                if (pos[xren+D[i][1]][yren+D[i][2]]==Q[3]) swap(Q[1],Q[3]);
                if (pos[xren+D[i][1]][yren+D[i][2]]==Q[1])
                    if (1<=xren+2*D[i][1] && xren+2*D[i][1]<=n && 1<=yren+2*D[i][2]
                            && yren+2*D[i][2]<=m && b[xren+2*D[i][1]][yren+2*D[i][2]]) {
                        Q[1]=pos[xren+2*D[i][1]][yren+2*D[i][2]];
                        for (int j=1; j<=3; j++)
                            for (int k=j+1; k<=3; k++)
                                if (Q[k]!=0 && Q[k]<Q[j]) swap(Q[j],Q[k]);
                        if (f[pos[xren+D[i][1]][yren+D[i][2]]][Q[1]][Q[2]][Q[3]]==-1) {
                            f[pos[xren+D[i][1]][yren+D[i][2]]][Q[1]][Q[2]][Q[3]]=sx+1;
                            c[++k][0]=pos[xren+D[i][1]][yren+D[i][2]];
                            c[k][1]=Q[1];
                            c[k][2]=Q[2];
                            c[k][3]=Q[3];
                        }
                    }
            }
        b[x1][y1]=true;
        b[x2][y2]=true;
        b[x3][y3]=true;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值