poj3322 Bloxorz 广搜BFS+地图类问题

原题处
题目思路:这道题主要是利用广搜解决“走地图”类问题,通过搜索问题状态,从走一步到走多步,最先的得到的结果一定是最小步数。

#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstdio>
#define MAX 510
using namespace std;
int n,m,d[MAX][MAX][3];
char s[MAX][MAX];
int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};//由于图是按照二维数组保存的
//所以左上角为零点,向下为x轴,向右为y轴
//依次代表左、右、上、下

//i=lie,左右上下依次对应j从0~3,下一步的位置
//如果横着躺,x,y,位于其靠左的位置,此时x相同,y差一
//如果竖着放,x,y位于其靠上的位置,此时y相同,x差一
int next_x[3][4]={{0,0,-2,1},{0,0,-1,1},{0,0,-1,2}};
int next_y[3][4]={{-2,1,0,0},{-1,2,0,0},{-1,1,0,0}};
int next_lie[3][4]={{1,1,2,2},{0,0,1,1},{2,2,0,0}};
struct Rec
{
    int x,y,lie;
};
queue<Rec>q;
Rec st,ed;
bool test(int x,int y){
    if(x<=0||x>n||y<=0||y>m) return 0;
    return 1;
}
bool valid(Rec next){
    if(!(test(next.x,next.y))) return 0;
    if(s[next.x][next.y]=='#') return 0;//位于禁点
    if(next.lie==0&&s[next.x][next.y]!='.') return 0;//站立时,为'#'
    if(next.lie==1&&s[next.x][next.y+1]=='#') return 0;
    if(next.lie==2&&s[next.x+1][next.y]=='#') return 0;
    return 1;
}
void pre(){//寻找并处理起点和终点,‘X’、‘O’变为‘.’,同时针对两个相邻起点按照上述处理,选择靠上还是靠左
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(s[i][j]=='O'){
                ed.x=i,ed.y=j;
                ed.lie=0;
                s[i][j]='.';
            }
            else if(s[i][j]=='X'){
                for(int k=0;k<3;k++){
                    if(test(i+dx[k],j+dy[k])&&s[i+dx[k]][j+dy[k]]=='X'){
                        st.x=min(i,i+dx[k]),st.y=min(j,j+dy[k]);
                        st.lie=k<2?1:2;
                        s[i][j]='.';
                        s[i+dx[k]][j+dy[k]]='.';
                        break;
                    }
                }
                if(s[i][j]=='X') st.x=i,st.y=j,st.lie=0;
            }
        }
    }
}
int bfs(){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            for(int k=0;k<3;k++){
                d[i][j][k]=-1;//初始化,来判定之前是否经过
            }
        }
    }
    while(q.size()) q.pop();//多组数据,清空队列
    d[st.x][st.y][st.lie]=0;
    q.push(st);
    while(q.size()){
        Rec now=q.front();q.pop();
        for(int i=0;i<4;i++){
            Rec next;
            next.x=now.x+next_x[now.lie][i];
            next.y=now.y+next_y[now.lie][i];
            next.lie=next_lie[now.lie][i];
            if(!valid(next)) continue;
            if(d[next.x][next.y][next.lie]==-1){
                d[next.x][next.y][next.lie]=d[now.x][now.y][now.lie]+1;
                q.push(next);
                if(next.x==ed.x&&next.y==ed.y&&next.lie==ed.lie) return d[next.x][next.y][next.lie];
            }
        }
    }
    return -1;
}
int main()
{
    while(cin>>n>>m&&n){
        for(int i=1;i<=n;i++) scanf("%s",s[i]+1);//一次输一行
        pre();
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++) cout<<s[i][j]<<" ";
            cout<<endl;
        }
        int ans=bfs();
        ans==-1?cout<<"Impossible":cout<<ans;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值