【NOIP模拟】箱子

【问题描述】 有个桌子长 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。

分析:测试t2,心态不好,没敢调

bfs+储存状态

首先我们将每个位置重新编号

用f[person][box1][box2][box3]来存储现在的状态,即人在person处,三个箱子分别在box1,box2,box3处的状态移动的最小步数。

先扩展人的移动(人不碰到箱子时),再扩展人与箱子一起的移动

#include<bits/stdc++.h>
using namespace std;
#define N 51
int n,m,cnt,t1,t2,sx,sy;
int e[N][N],pos[N][N];
int f[N][N][N][N];
int dx[5]={0,0,0,1,-1};
int dy[5]={0,1,-1,0,0};
int box[N],button[N],cx[N],cy[N],ope[N];
bool vis[N][N];
char c[N];
struct email
{
    int person,box1,box2,box3;
}st;
email makepair(int x,int y,int w,int z)
{
    email a;
    a.person=x;a.box1=y;a.box2=w;a.box3=z;
    return a;
}
queue<email>que;
int main()
{
    scanf("%d%d",&n,&m);
    memset(f,-1,sizeof(f));
    memset(vis,true,sizeof(vis));
    for(int i=1;i<=n;i++)
    {
        scanf("%s",c);
        for(int j=1;j<=m;j++)
        {
       
            e[i][j]=c[j-1]-'0';
            pos[i][j]=++cnt;
            cx[cnt]=i;cy[cnt]=j;
            if(e[i][j]==4){sx=i,sy=j;e[i][j]=0;}
            if(e[i][j]==2)box[++t1]=pos[i][j];
            if(e[i][j]==3)button[++t2]=pos[i][j];    
            if(e[i][j]==1)vis[i][j]=false;    
        }
    }
    f[pos[sx][sy]][box[1]][box[2]][box[3]]=0;
    st.person=pos[sx][sy];st.box1=box[1];st.box2=box[2];st.box3=box[3];
    que.push(st);
    while(!que.empty())
    {
        email u=que.front();que.pop();
        int ps=u.person,b1=u.box1,b2=u.box2,b3=u.box3;
        int x0=cx[ps],y0=cy[ps];
        
        int x1=cx[b1],y1=cy[b1];
        int x2=cx[b2],y2=cy[b2];
        int x3=cx[b3],y3=cy[b3];
        vis[x1][y1]=false;vis[x2][y2]=false;vis[x3][y3]=false;
        if(b1==button[1]&&b2==button[2]&&b3==button[3])
        {
            printf("%d",f[ps][b1][b2][b3]);
            return 0;
        }
        int num=f[ps][b1][b2][b3];
        for(int i=1;i<=4;i++)
        {
            int p=x0+dx[i],q=y0+dy[i];

           if(p<1||p>n||q<1||q>m)continue;
            if(vis[p][q]&&f[pos[p][q]][b1][b2][b3]==-1)
            {
                f[pos[p][q]][b1][b2][b3]=num+1;
                que.push(makepair(pos[p][q],b1,b2,b3));
            }
            ope[1]=b1,ope[2]=b2,ope[3]=b3;
            if(pos[p][q]==ope[2])swap(ope[1],ope[2]);
            if(pos[p][q]==ope[3])swap(ope[3],ope[1]);
            if(pos[p][q]==ope[1])
            {             
                int pp=p+dx[i],qq=q+dy[i];
                if(pp<1||pp>n||qq<1||qq>m||!vis[pp][qq])continue;
                ope[1]=pos[pp][qq];
                for(int j=1;j<=3;j++)
                    for(int k=j+1;k<=3;k++)
                        if(ope[k]&&ope[k]<ope[j])
                            swap(ope[k],ope[j]);
                
                if(f[pos[p][q]][ope[1]][ope[2]][ope[3]]==-1)
                {
                    f[pos[p][q]][ope[1]][ope[2]][ope[3]]=num+1;
                    que.push(makepair(pos[p][q],ope[1],ope[2],ope[3]));
                }
                
            }
        }
        vis[x1][y1]=true;vis[x2][y2]=1;vis[x3][y3]=1;
    }
    return 0;
}    

“Make my parents proud,and impress the girl I like.”
原文地址:https://www.cnblogs.com/NSD-email0820/p/9440269.html