题目描述 箱子
【问题描述】
有个桌子长 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;
}
}