洛谷P1825 [USACO11OPEN] Corn Maze S

Corn Maze S

输入格式

第一行:两个用空格隔开的整数 N 和 M。

第 2∼N+1 行:第 i+1 行描述了迷宫中的第 i 行的情况(共有M个字符,每个字符中间没有空格)。

输出格式

一个整数,表示起点到出口所需的最短时间。

题意翻译

奶牛们去一个 N×M 玉米迷宫,2≤N≤300,2≤M≤300。

迷宫里有一些传送装置,可以将奶牛从一点到另一点进行瞬间转移。这些装置可以双向使用。

如果一头奶牛处在这个装置的起点或者终点,这头奶牛就必须使用这个装置,奶牛在传送过后不会立刻进行第二次传送,即不会卡在传送装置的起点和终点之间来回传送。

玉米迷宫除了唯一的一个出口都被玉米包围。

迷宫中的每个元素都由以下项目中的一项组成:

  1. 玉米,# 表示,这些格子是不可以通过的。
  2. 草地,. 表示,可以简单的通过。
  3. 传送装置,每一对大写字母 A 到 Z 表示。
  4. 出口,= 表示。
  5. 起点, @ 表示

奶牛能在一格草地上可能存在的四个相邻的格子移动,花费 1 个单位时间。从装置的一个结点到另一个结点不花时间。

输入输出样例

输入 #1复制

5 6
###=##
#.W.##
#.####
#.@W##
######

输出 #1复制

3

说明/提示

例如以下矩阵,N=5,M=6。

###=##
#.W.##
#.####
#.@W##
######

唯一的一个装置的结点用大写字母 W 表示。

最优方案为:先向右走到装置的结点,花费一个单位时间,再到装置的另一个结点上,花费 0 个单位时间,然后再向右走一个,再向上走一个,到达出口处,总共花费了 3 个单位时间。

代码: 

#include <bits/stdc++.h>
using namespace std;
int n,m,x,y,x2,y2;
char sn[410][410];//存迷宫
int dis[410][410];//存到达某点最短距离
vector<int> e[51];//存传送门
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};//向上下左右移动
void bfs(int a,int b){
    queue<pair<int,int> > q;
    q.push({a,b});//入队
    while(q.size()){
        pair<int,int> now=q.front();//取队头
        q.pop();//出队
        int a=now.first,b=now.second;
        for(int i = 0;i<=3;i++){//移动
            int xx=a+dx[i],yy=b+dy[i];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&sn[xx][yy]=='.'&&dis[xx][yy]>dis[a][b]+1){
                //判断是否越界 是否是草地 是否能得到更短距离
                //如果是草地,可以走
                q.push({xx,yy});//入队
                dis[xx][yy]=dis[a][b]+1;          
            }
            else if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&sn[xx][yy]>='A'&&sn[xx][yy]<='Z'){
                //判断是否越界 是否是传送门
                //如果是传送门,找到此传送门对应的终点
                int d=sn[xx][yy]-'A'+1;//转化为编号
                int xx1=e[d][0],yy1=e[d][1],xx2=e[d][2],yy2=e[d][3];
                //xx1代表其中一个传送门的横坐标,yy1纵坐标
                //xx2代表另一个传送门的横坐标,yy2纵坐标
                //下面要注意!!调了好久
                if(xx==xx1&&yy==yy1&&dis[xx2][yy2]>dis[a][b]+1){
                    //如果xx,yy为xx1,yy1这个传送门,那么xx,yy这个点说明没有走到,只有停留才视为走到这个点
                    //走到的是xx2,yy2这个传送门,可以停留
                    dis[xx2][yy2]=dis[a][b]+1;
                    q.push({xx2,yy2});
                }else if(xx==xx2&&yy==yy2&&dis[xx1][yy1]>dis[a][b]+1){
                    //如果xx,yy为xx2,yy2这个传送门,那么xx,yy这个点说明没有走到,只有停留才视为走到这个点
                    //走到的是xx1,yy1这个传送门,可以停留                    
                    dis[xx1][yy1]=dis[a][b]+1;
                    q.push({xx1,yy1});                    
                }
            }
            else if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&sn[xx][yy]=='='&&dis[xx][yy]>dis[a][b]+1){
                //判断是否到达出口,如果到达,存值并且可以直接结束宽搜
                dis[xx][yy]=dis[a][b]+1;       
                return;
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=m;j++){
            cin >> sn[i][j];
            if(sn[i][j]=='@') x=i,y=j;//记录起点
            if(sn[i][j]=='=') x2=i,y2=j;//记录出口
            if(sn[i][j]>='A'&&sn[i][j]<='Z'){//记录传送门
                int id=sn[i][j]-'A'+1;//将字符转化为编号 例如A编号为1
                e[id].push_back(i);
                e[id].push_back(j);
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            dis[i][j]=1e6;//初始化 求最小值
        }
    }
    dis[x][y]=0;//初始化起点距离为0
    bfs(x,y);//深搜
    cout << dis[x2][y2];
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值