BFS + 贪心 - 会拐弯的眼睛 - 中国计量大学现代科技学院第四届“中竞杯”程序设计校赛

26 篇文章 0 订阅

BFS - 会拐弯的眼睛 - 中国计量大学现代科技学院第四届“中竞杯”程序设计校赛

题意:

给 定 一 个 n × m 的 矩 阵 , 计 算 从 起 点 到 终 点 , 最 少 需 要 ′ ′ 拐 弯 ′ ′ 几 次 。 给定一个n×m的矩阵,计算从起点到终点,最少需要''拐弯''几次。 n×m

输入描述:

输 入 第 一 行 六 个 正 整 数 n , m 描 述 地 图 大 小 , s t a r t x , s t a r t y , e n d x , e n d y 描 述 起 点 , 终 点 。   保 证 : 1 ≤ n , m ≤ 5000 , 0 ≤ s t a r t x , e n d x ≤ n − 1 , 0 ≤ s t a r t y , e n d y ≤ m − 11 ≤ n , m ≤ 5000 , 0 ≤ s t a r t x , e n d x ≤ n − 1 , 0 ≤ s t a r t y , e n d y ≤ m − 1 接 下 来 n 行 , 每 行 一 个 长 度 为 m 的 01 串 , 0 代 表 可 以 走 的 空 地 , 1 代 表 不 能 走 的 墙 壁 输入第一行六个正整数 n,m 描述地图大小,startx, starty, endx, endy 描述起点,终点。 \\\ \\保证:\\ 1 \leq n,m \leq 5000,0 \leq startx,endx \leq n-1, \\0 \leq starty,endy \leq m-11≤n,m≤5000,\\0≤startx,endx≤n−1,0≤starty,endy≤m−1\\接下来 n 行,每行一个长度为 m 的 01 串,0 代表可以走的空地,1 代表不能走的墙壁 nmstartx,starty,endx,endy :1nm50000startx,endxn1,0starty,endym11nm50000startx,endxn1,0starty,endym1nm0101

输出描述:

输 出 一 行 一 个 正 整 数 表 示 答 案 。 输出一行一个正整数表示答案。

若 无 法 到 达 终 点 , 则 输 出 − 1. 若无法到达终点,则输出-1. 1.

示例1
输入

3 3 0 0 2 2
000
110
110

输出

1

示例2
输入

3 3 0 0 2 2
001
101
100

输出

2

分析:

本 题 很 容 易 想 到 用 B F S 来 求 解 , 关 键 在 于 , 如 何 考 虑 ′ ′ 拐 弯 ′ ′ 。 本题很容易想到用BFS来求解,关键在于,如何考虑''拐弯''。 BFS

参 照 B F S 的 算 法 思 想 , 我 们 可 以 把 无 需 拐 弯 可 直 通 的 点 看 作 是 同 一 层 结 点 。 参照BFS的算法思想,我们可以把无需拐弯可直通的点看作是同一层结点。 BFS

对 于 每 一 个 结 点 , 我 们 从 上 下 左 右 四 个 方 向 不 断 扩 展 , 直 至 不 能 扩 展 为 止 。 对于每一个结点,我们从上下左右四个方向不断扩展,直至不能扩展为止。

贪 心 地 去 想 , 因 为 朝 同 一 个 方 向 扩 展 的 花 费 为 0 , 那 么 对 同 一 方 向 , 我 们 应 当 尽 量 多 地 扩 展 新 的 结 点 。 贪心地去想,因为朝同一个方向扩展的花费为0,那么对同一方向,我们应当尽量多地扩展新的结点。 0

这 样 就 能 够 保 证 , 每 个 点 第 一 次 被 扩 展 到 时 就 是 最 近 距 离 ( 最 少 花 费 ) 。 这样就能够保证,每个点第一次被扩展到时就是最近距离(最少花费)。 ()

仔细去思考这个做法:

实 际 上 我 们 是 把 每 个 结 点 上 下 左 右 能 够 直 达 的 所 有 未 曾 遍 历 过 的 结 点 看 作 是 同 一 层 结 点 了 。 实际上我们是把每个结点上下左右能够直达的所有未曾遍历过的结点看作是同一层结点了。

每 次 操 作 我 们 把 同 一 层 的 结 点 全 都 入 队 , 继 续 再 做 同 样 地 操 作 。 每次操作我们把同一层的结点全都入队,继续再做同样地操作。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<unordered_map>
#include<vector>

#define P pair<int,int>
#define x first
#define y second
#define ll long long

using namespace std;

const int N = 5010, inf = 0x3f3f3f3f;

struct node
{
    int x, y, dir, step;
};
char str[N][N];
int n, m;
node S, E;
int dir[4][2]={{1,0}, {-1,0}, {0,1}, {0,-1}};
int dis[N][N];

bool check(int x,int y)
{
    if(x<0 || x>=n || y<0 ||y>=m || str[x][y]=='1') return false;
    return true;
}

int bfs()
{
    memset(dis,0x3f,sizeof dis);
    queue<node> Q;
    for(int i=0;i<4;i++) Q.push({S.x,S.y,-1,-1});
    dis[S.x][S.y]=-1;
    
    while(Q.size())
    {
        node u = Q.front();
        Q.pop();
        
        for(int i=0;i<4;i++)
        {
            if(i==u.dir) continue;
            
            for(int j=1;;j++)
            {
                int x = u.x + dir[i][0]*j, y = u.y + dir[i][1]*j;
                if(!check(x,y)) break;
                if(dis[x][y]!=inf) continue;
                
                dis[x][y]=u.step+1;
                if(x==E.x && y==E.y) return dis[x][y];
                Q.push({x,y,i,dis[x][y]});
            }
        }
    }
    return -1;
}


int main()
{
    scanf("%d%d%d%d%d%d",&n,&m,&S.x,&S.y,&E.x,&E.y);
    for(int i=0;i<n;i++) scanf("%s",str[i]);
    printf("%d\n",bfs());
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值