POJ-1475:Pushing Boxes(嵌套bfs或bfs+A*算法)


题目链接:点击打开链接


题目大意:

一个人要将箱子推到终点,输出推的最少次数的路径,若最少次数相同,输出步数最少。


解题思路:

刚上来没看清题目,以为就是步数最少,刷刷刷敲完发现样咧没过,但是我的代码结果比他还短,以为样例错了,神tm就交了一发,然后wa了。。。

后来仔细看了一下题目,原来是推的次数最少。想了一下,那么肯定要对箱子bfs,对箱子bfs的过程中对人的位置进行bfs,因为要推箱子的话,只有一个位置能推。那么对当前人的位置到这个位置bfs就好,实现稍微注意一下。还听说这道题是假特判,不清楚,反正我是没遇到啥问题。总体来说的话呢就是个嵌套bfs,但是不知道为啥,大佬做法跟我一样但是人家大佬是0msA的,我需要200+ms,可能是代码太过丑陋。。。

这题还有第二种做法,就是利用A星算法,A星算法其实最主要的就是确定优先级的问题。。。

这道题我想了一下,就把我第一次理解错题意的代码拿了出来,然后在struct 里面加上两个 关键字 push step 一个是推箱子次数,一个是总步数,手写好优先级,让推箱子次数少的在前面,如果次数相等就让步数少的在前面。再把队列改为优先队列,然后就A了Orz,但是用时1000+ms,可能是我写的问题,不过感觉这种方法确实没有嵌套bfs快。。。

以下贴两次的代码。。。

首先是嵌套bfs,时间200+ms


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <set>
#include <functional>
#define rank ra
#define lson rt<<1
#define rson rt<<1|1
#define pb push_back
#define hash haha
using namespace std;
typedef long long ll;
int n,m;
bool vis[25][25][25][25];   //人箱状态
bool v[25][25];         //对人单独bfs 人的状态
char ma[25][25];
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
int px,py,vx,vy,ex,ey;  //分别记录人箱子起始位置和终点
string ans;
struct nodes    //对人单独bfs用的struct
{
    int x,y;
    string dir;
};
struct node     //箱子bfs
{
    int px,py,vx,vy;
    string dir;
};
char vc(int i)
{
    if(i==0)
        return 'N';
    if(i==1)
        return 'S';
    if(i==2)
        return 'W';
    return 'E';
}
char vs(int i)
{
    if(i==0)
        return 'n';
    if(i==1)
        return 's';
    if(i==2)
        return 'w';
    return 'e';
}
bool check(int x,int y)     //检查点是否合理
{
    if(x>=1&&x<=n&&y>=1&&y<=m&&ma[x][y]!='#')
        return 1;
    return 0;
}
string bfs1(int sx,int sy,int kx,int ky,int gx,int gy)  //对人单独bfs 注意箱子也不能通过
{
    memset(v,0,sizeof(v));
    queue<nodes> que;
    nodes st;
    st.x=sx;st.y=sy;
    que.push(st);
    v[st.x][st.y]=1;
    string res="Impossible.";
    nodes k1;
    while(!que.empty())
    {
        nodes k=que.front();
        que.pop();
        if(k.x==kx&&k.y==ky)
        {
            res=k.dir;
            break;
        }
        for(int i=0;i<4;i++)
        {
            int xx=k.x+dx[i];
            int yy=k.y+dy[i];
            if(check(xx,yy)&&v[xx][yy]==0&&(xx!=gx||yy!=gy))
            {
                k1.x=xx;
                k1.y=yy;
                k1.dir=k.dir+vs(i);
                que.push(k1);
                v[xx][yy]=1;
            }
        }
    }
    return res;
}
void bfs()
{
    memset(vis,0,sizeof(vis));
    queue<node> que;
    node st;
    st.px=px;st.py=py;
    st.vx=vx;st.vy=vy;
    que.push(st);
    vis[px][py][vx][vy]=1;  //记录初始位置
    ans="Impossible.";
    node k1;
    while(!que.empty())
    {
        node k=que.front();
        que.pop();
        if(k.vx==ex&&k.vy==ey)
        {
            ans=k.dir;
            break;
        }
        for(int i=0;i<4;i++)
        {
            int xx=k.vx+dx[i];   //判断箱子能否被人在后面推一格
            int yy=k.vy+dy[i];
            int bx=k.vx-dx[i];
            int by=k.vy-dy[i];
            if(check(xx,yy)&&check(bx,by)&&vis[k.vx][k.vy][xx][yy]==0)
            {
                string tem,re;
                k1.px=k.vx;k1.py=k.vy;
                k1.vx=xx;k1.vy=yy;
                re=bfs1(k.px,k.py,bx,by,k.vx,k.vy);     //注意传箱子的位置
                if(re==ans)     //人不能到达则跳过
                    continue;
                tem=k.dir+re;
                k1.dir=tem+vc(i);
                que.push(k1);
                vis[k.vx][k.vy][xx][yy]=1;
            }
        }
    }
}
int main()
{
    int kase=0;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)
            break;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                scanf(" %c",&ma[i][j]);
                if(ma[i][j]=='S')
                {
                    px=i;
                    py=j;
                }
                if(ma[i][j]=='B')
                {
                    vx=i;
                    vy=j;
                }
                if(ma[i][j]=='T')
                {
                    ex=i;
                    ey=j;
                }
            }
        }
        bfs();
        printf("Maze #%d\n",++kase);
        cout<<ans<<endl;
        printf("\n");
    }
    return 0;
}



A星算法,其实也就是正常bfs中加了关键字和优先队列。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <set>
#include <functional>
#define rank ra
#define lson rt<<1
#define rson rt<<1|1
#define pb push_back
#define hash haha
using namespace std;
typedef long long ll;
int n,m;
bool vis[25][25][25][25];   //记录状态
char ma[25][25];        
int dx[4]={0,-1,1,0};
int dy[4]={1,0,0,-1};
int px,py,vx,vy,ex,ey;
string ans;
struct node
{
    int px,py,vx,vy;
    int push,step;      //分别为推箱子次数和总步数
    string dir;
    bool operator<(const node &g) const     //手写优先级将小的放在队列前面
    {
        if(push==g.push)
            return step>g.step;
        return push>g.push;
    }
};
char vc(int i)
{
    if(i==0)
        return 'E';
    if(i==1)
        return 'N';
    if(i==2)
        return 'S';
    return 'W';
}
char vs(int i)
{
    if(i==0)
        return 'e';
    if(i==1)
        return 'n';
    if(i==2)
        return 's';
    return 'w';
}
void bfs()
{
    memset(vis,0,sizeof(vis));
    priority_queue<node> que;   //使用优先队列
    node st;
    st.px=px;st.py=py;
    st.vx=vx;st.vy=vy;
    st.step=st.push=0;
    que.push(st);
    vis[px][py][vx][vy]=1;
    ans="Impossible.";
    node k1;
    while(!que.empty())
    {
        node k=que.top();
        que.pop();
        if(k.vx==ex&&k.vy==ey)
        {
            ans=k.dir;
            break;
        }
        for(int i=0;i<4;i++)
        {
            int xx=k.px+dx[i];
            int yy=k.py+dy[i];
            if(xx<1||xx>n||yy<1||yy>m||ma[xx][yy]=='#'||vis[xx][yy][k.vx][k.vy])
                continue;
            if(xx==k.vx&&yy==k.vy)  //如果人走的这一步推动了箱子
            {
                int tx=xx+dx[i];
                int ty=yy+dy[i];
                if(tx<1||tx>n||ty<1||ty>m||ma[tx][ty]=='#'||vis[xx][yy][tx][ty])
                    continue;
                k1.px=xx;k1.py=yy;
                k1.vx=tx;k1.vy=ty;
                k1.push=k.push+1;   //推箱子次数+1
                k1.step=k.step+1;
                k1.dir=k.dir+vc(i);
                que.push(k1);
                vis[xx][yy][tx][ty]=1;
            }
            else    //正常bfs
            {
                k1.px=xx;k1.py=yy;
                k1.vx=k.vx;k1.vy=k.vy;
                k1.push=k.push;
                k1.step=k.step+1;
                k1.dir=k.dir+vs(i);
                que.push(k1);
                vis[xx][yy][k.vx][k.vy]=1;
            }
        }
    }
}
int main()
{
    int kase=0;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)
            break;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                scanf(" %c",&ma[i][j]);
                if(ma[i][j]=='S')
                {
                    px=i;
                    py=j;
                }
                if(ma[i][j]=='B')
                {
                    vx=i;
                    vy=j;
                }
                if(ma[i][j]=='T')
                {
                    ex=i;
                    ey=j;
                }
            }
        }
        bfs();
        printf("Maze #%d\n",++kase);
        cout<<ans<<endl;
        printf("\n");
    }
    return 0;
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值