(新版)SJTU-OJ-1035. 酒吧

题目描述

莘庄有很多酒吧,侯不会和苏前端打算约在其中一个酒吧见面。为了节省时间,他们希望从各自的家赶往酒吧的时间之和尽可能少,现在请你为他们挑选一个酒吧。莘庄可以被划分为 n × m n \times m n×m 个单元格,每个单元格可能是侯不会的家(‘H’)、苏前端的家(‘S’)、障碍物(’#’)、空地(’.’)或者酒吧(‘B’),其中障碍物所在位置不能通行,其余单元格均可通行,保证至少有一个酒吧两人都可以到达。侯不会和苏前端每分钟可以向上下左右移动一格。求侯不会和苏前端各自从家到酒吧的时间之和的最小值。

输入格式

第一行包含两个整数 n , m n, m n,m。( 2 ≤ n , m ≤ 1000 2 \le n, m \le 1000 2n,m1000)

接下来 n n n 行,每行有 m m m 个用空格隔开的字符。

'H’代表侯不会的家的位置。

'S’代表苏前端的家的位置。

'#'代表障碍物的位置。

'.'代表可通行的位置。

'B’代表酒吧的位置。

输出格式

一个整数,表示侯不会和苏前端各自从家到酒吧的时间之和的最小值。

样例输入

4 4
H.#B
....
.#..
B..S

样例输出

6

数据范围

对于 20 % 20\% 20%的数据, 2 ≤ n , m ≤ 20 2 \le n, m \le 20 2n,m20

对于另外 20 % 20\% 20%的数据,地图上没有障碍物。

对于另外 20 % 20\% 20%的数据,地图上只有一个酒吧。

对于 100 % 100\% 100%的数据, 2 ≤ n , m ≤ 1000 2 \le n, m \le 1000 2n,m1000

题目解答

      什么叫做水题?如果你做完了上一道题,那么这道题是实力水题!(新版)SJTU-OJ-1028.采购 传送门
      什么?没有做过上一题?(新版)SJTU-OJ-1028.采购 传送门
      什么?不会深度优先搜索?(新版)SJTU-OJ-1028.采购 传送门
      这两个题目完全一样,都是途径一个点的问题,完全没有考的必要,做一道就可以,为了偷懒,我连上一道题目的shop都没有改,放AC代码!不解释,太简单了。只需要改#,H,B,S就可以。

// 所有坐标x代表行数,y代表列数!
// 本题坐标采用0-base!

// 这也太水了吧,就是之前那个国王题目,复制粘贴
// 伞店我都懒得吧shop改成bar,凑合看看就好

#include <iostream>
#include <queue>
#include <cstring>
#include <cmath>
using namespace std;

class shop
{
    public:
        int x;
        int y;
};

class node
{
    public:
        int x;
        int y;
}sh[1000000] = { 0,0 };

char testmap[1010][1010];
int step[1010][1010];
// 定义增量x,y 数组,
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};
// 定义shop数组

int shopnum = 0;
int m, n;

bool bfs_CheckNextstep(node checkobject)
{
    if (checkobject.x < 0 || checkobject.x >= n)
        return false;
    if (checkobject.y < 0 || checkobject.y >= m)
        return false;
    if (testmap[checkobject.x][checkobject.y] == '#')
        return false;
    if (step[checkobject.x][checkobject.y] != 0)
        return false;
    else
        return true;
    // if (nxt.x >= 0 && nxt.x < m && nxt.y >= 0 && nxt.y < n && step[nxt.x][nxt.y] == 0 && testmap[nxt.x][nxt.y] != 1)
    //     return true;
    // else
    //     return false;
}

// 广度优先搜索,传入的时候传入一个节点node!
void bfs_Main(node departure)
{
    memset(step, 0, sizeof(step));
    // 首先定义一个队列!
    queue<node> bfsque;
    bfsque.push(departure);
    node currentplace, nextplace;
    while (!bfsque.empty())
    {
        currentplace = bfsque.front();
        bfsque.pop(); // 把最前面的元素弹出去!
        for (int i = 0; i < 4; i++)
        {
            nextplace.x = currentplace.x + dx[i];
            nextplace.y = currentplace.y + dy[i];
            if (bfs_CheckNextstep(nextplace) == true)
            {
                step[nextplace.x][nextplace.y] = step[currentplace.x][currentplace.y] + 1;
                bfsque.push(nextplace);
            }
        }
    }
}

int main()
{
    cin >> n >> m;
    node departure, destination;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> testmap[i][j];
            if (testmap[i][j] == 'H')     
            {
                departure.x = i;
                departure.y = j;
            }
            if (testmap[i][j] == 'S')     
            {
                destination.x = i;
                destination.y = j;
            }
            if (testmap[i][j] == 'B')     
            {
                sh[shopnum].x = i;
                sh[shopnum].y = j;
                shopnum++;
            }
        }
    }

    int a[10000] = {0};
    int b[10000] = {0};
    bfs_Main(departure);
    for (int i = 0; i < shopnum; i++)
    {
        a[i] = step[sh[i].x][sh[i].y];
    }

    bfs_Main(destination);
    for (int i = 0; i < shopnum; i++)
    {
        b[i] = step[sh[i].x][sh[i].y];
    }

    long int ans = 1e8;
    long int temp;
    for (int i = 0; i < shopnum; ++i) 
    {
        if (a[i] > 0 && b[i] > 0)
        {
            temp = a[i] + b[i];
            ans = min(ans, temp);
        }  
    }
    cout << ans;
    system("pause");
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值