《算法竞赛从入门到进阶》心得及相关题解015--bfs--hdu1180


题目意思:hdu1180,给你一张图,图上有些障碍物和楼梯,每走一步楼梯的状态会改变。问从起点到终点至少要多少步。
解题思路:标准bfs题目,每次要走新的一步时,判断如下:

1.如果新的位置不在图内,或在图内但是*时或已经访问过时,则不处理;
2.如果新位置是.时,移动到新位置步数加1入队列;
3.左右移动时如果楼梯刚好是’-‘则可越过;上下移动,如果楼梯刚好是’|'也刚好可越过。都移动到新位置则步数加1队列;
4.否则原地等待楼梯转到正确方向。


1.初始化时T必须改为. 否则搜索不到; 2.设置一个变量pStep记录上一个节点的步数,如果当前队列front节点的步数step与pStep不相等,则要改变楼梯的状态。
代码明细:
//probID: hdu1180
//author: WiselyQY
//date: 2021-01-03
#include <bits/stdc++.h>
using namespace std;

const int INF=1<<30;
//用于记录目前的位置和已用的时间
struct Node
{
    int x,y,step;
};
int m,n,vis[25][25],sx,sy,ex,ey,ans;  //(sx,sy)为起点坐标,(ex,ey)为终点坐标
char g[25][25];
queue<Node> q;
const int dx[]={1,0,-1,0}, dy[]={0,1,0,-1}; //DRUL四个方向
void changeState()  //改变楼梯的状态
{
    for(int i=0; i<m; i++)
        for(int j=0; j<n; j++)    
            if(g[i][j]=='-') g[i][j]='|';
            else if (g[i][j]=='|') g[i][j]='-';
}
int in(int x, int y)
{
    return x>=0 && x<m && y>=0 && y<n;
}
void bfs()
{
    Node u;
    u.x=sx; u.y=sy; u.step=0;
    memset(vis,0,sizeof(vis));
    vis[u.x][u.y]=1;
    while(!q.empty()) q.pop();
    q.push(u);
    int pStep=0; //用于记录上一个从q队列pop出来的结点的步数
    while(!q.empty())
    {
        u=q.front(); q.pop();
        int x=u.x, y=u.y, step=u.step;
        if(x==ex && y==ey) {ans=step; return;}//找到结果,返回
        if(pStep!=step) {pStep=step; changeState();} //如果当前步数和上一个节点的步数不同,则证明步数已增加1,必须改变楼梯的状态
        for(int i=0; i<4; i++)
        {
            int nx=x+dx[i], ny=y+dy[i];
            if(!in(nx,ny) || g[nx][ny]=='*' || vis[nx][ny]) continue; //不在范围内,或在范围内但不可行或已经访问过,则不用处理
            Node nu;
            if(g[nx][ny]=='.')  //移动到新位置
            {
                vis[nx][ny]=1;
                nu.x=nx; nu.y=ny; nu.step=step+1;
                q.push(nu);                                
            }
            //i为1和3时是左右移动,如果楼梯刚好是'-'则可越过;i为0和2时是上下移动,如果楼梯刚好是'|'也刚好可越过
            else if((g[nx][ny]=='-' && i%2) || (g[nx][ny]=='|' && !(i%2))) 
            {
                nx+=dx[i]; ny+=dy[i];
                if(!in(nx,ny) || g[nx][ny]=='*' || vis[nx][ny]) continue;
                vis[nx][ny]=1;
                nu.x=nx; nu.y=ny; nu.step=step+1;
                q.push(nu);
            }
            else //楼梯位置与当前方向刚好相反,原地等待一步
            {
                nu=u;
                nu.step+=1;
                q.push(nu);
            }                            
        }        
    }
}
int main()
{
    clock_t start,end;
    start=clock();
#ifndef ONLINE_JUDGE
    freopen(R"(D:\code\hdu\1180\in.txt)","r",stdin);
#endif
    while(cin>>m>>n)
    {
        for(int i=0; i<m; i++)
            for(int j=0; j<n; j++)
            {
                cin>>g[i][j];
                if(g[i][j]=='S') {sx=i; sy=j; g[i][j]='.';}
                if(g[i][j]=='T') {ex=i; ey=j; g[i][j]='.';}//必须把重点从T改为. 不然搜索不到
            }
        ans=INF;
        bfs();
        cout<<ans<<endl;        
    }
    end=clock();
    //printf("time=%lfs\n",(double)(end-start)/1000);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值