华为OD统一考试 - 欢乐的周末

题目描述

小华和小为是很要好的朋友,他们约定周末一起吃饭。

通过手机交流,他们在地图上选择了多个聚餐地点(由于自然地形等原因,部分聚餐地点不可达),求小华和小为都能到达的聚餐地点有多少个?

输入描述

第一行输入 m 和 n

  • m 代表地图的长度
  • n 代表地图的宽度

第二行开始具体输入地图信息,地图信息包含:

  • 0 为通畅的道路
  • 1 为障碍物(且仅1为障碍物)
  • 2 为小华或者小为,地图中必定有且仅有2个 (非障碍物)
  • 3 为被选中的聚餐地点(非障碍物)

输出描述

可以被两方都到达的聚餐地点数量,行末无空格。

备注

地图的长宽为 m 和 n,其中:

  • 4 ≤ m ≤ 100
  • 4 ≤ n ≤ 100

聚餐的地点数量为 k,则

  • 1< k ≤ 100

用例

输入

4 4

2 1 0 3

0 1 2 1

0 3 0 0

0 0 0 0

输出

2

说明

第一行输入地图的长宽为3和4。

第二行开始为具体的地图,其中:3代表小华和小明选择的聚餐地点;2代表小华或者小明(确保有2个);0代表可以通行的位置;1代表不可以通行的位置。

此时两者能都能到达的聚餐位置有2处。

输入

4 4

2 1 2 3

0 1 0 0

0 1 0 0

0 1 0 0

输出

0

说明

第一行输入地图的长宽为4和4。

第二行开始为具体的地图,其中:3代表小华和小明选择的聚餐地点;2代表小华或者小明(确保有2个);0代表可以通行的位置;1代表不可以通行的位置。

由于图中小华和小为之间有个阻隔,此时,没有两人都能到达的聚餐地址,故而返回0。

题目解析

本题可以使用并查集解题。

小华和小为想去同一个餐厅,那么必然小华和小为和餐厅是可以连通,如果它们不能连通,则去不了同一个餐厅。

因此,我们可以遍历矩阵中每一个元素,将它和其上下左右元素进行连接,需要注意的是如果遍历的元素本身是1,或者其上下左右的元素是1,则不进行连接。

这样的话,遍历完矩阵后,就可以得到一个连通图。

同时在遍历矩阵过程中,记录小华、小为(值为2),以及餐厅(值为3)的位置,遍历结束后,首先看小华和小为是不是同一个祖先,若不是,则二者不可连通,就更别说去同一个餐厅了,因此返回0。若二者可以连通,则再看每一个餐厅的祖先是否和华为的祖先相同,若相同则计数++,这样就可以得到小华,小为去的同一个餐厅的数量了。

本题输入中

  • m 代表地图的长度
  • n 代表地图的宽度

长度 m 指的是地图矩阵的行数,宽度 n 指的是地图矩阵的列数。


import Foundation

func ODTest_2_42() {
    print("输入描述")
    print("第一行输入 m 和 n, m 代表地图的长度 n 代表地图的宽度")
    let MN = (readLine() ?? "").split(separator: " ").map { Int($0) ?? 0 }
    let M = MN[0], N = MN[1]

    print("第二行开始具体输入地图信息,地图信息包含:")
    // 矩阵
    print("第二行开始,是M行N列的像素的二维数组,仅包含像素1和5")
    var matrix = Array(repeating: Array(repeating: 0, count: N), count: M)
    for i in 0 ..< M {
        matrix[i] = (readLine() ?? "").split(separator: " ").map { Int($0) ?? 0 }
    }
    print("可以被两方都到达的聚餐地点数量,行末无空格。")
    // 记录小华,小为的位置
    var huawei: [Int] = []
    // 记录餐厅的位置
    var restaurants: [Int] = []

    let rows = matrix.count
    let cols = matrix[0].count
    let ufs = UnionFindSet(rows * cols)
    getResult()
    
    // 小华所在连通分量的根
    let hua_fa = ufs.find(huawei[0])
    // 小为所在连通分量的根
    let wei_fa = ufs.find(huawei[1])
    // 如果小华和小为的不属于同一个连通分量,则二人无法去往相同餐厅
    if hua_fa != wei_fa {
        print("0")
        return
    }
    // 找出和小华、小为在同一个连通分量里面的餐厅
    var ans = 0
    for restaurant in restaurants {
        if ufs.find(restaurant) == hua_fa {
            ans += 1
        }
    }
    print("\(ans)")

    func getResult() {
        // 上下左右四个方向偏移量
        let offsets = [
            [-1, 0],
            [1, 0],
            [0, -1],
            [0, 1],
        ]
        for i in 0 ..< rows {
            for j in 0 ..< cols {
                if matrix[i][j] != 1 {
                    // 二维坐标(i, j) 转为 一维坐标pos
                    let pos = i * cols + j
                    if matrix[i][j] == 2 {
                        // 收集小华,小为的位置
                        huawei.append(pos)
                    } else if matrix[i][j] == 3 {
                        // 收集餐厅的位置
                        restaurants.append(pos)
                    }

                    for offset in offsets {
                        let newI = i + offset[0]
                        let newJ = j + offset[1]
                        if
                            newI >= 0 &&
                            newI < rows &&
                            newJ >= 0 &&
                            newJ < cols &&
                            matrix[newI][newJ] != 1
                        {
                            // 如果(i,j)和(newI,newJ)位置都是非1,则合并
                            ufs.union(pos, newI * cols + newJ)
                        }
                    }
                }
            }
        }
    }

    // 并查集实现
    class UnionFindSet {
        var father: [Int] = []

        init(_ N: Int) {
            father = Array(repeating: 0, count: N)
            for i in 0 ..< N {
                father[i] = i
            }
        }

        func find(_ xPoint: Int) -> Int {
            if xPoint != father[xPoint] {
                father[xPoint] = find(father[xPoint])
                return father[xPoint]
            }
            return xPoint
        }

        // 合并接触 如 F(1) = 0, F(3) = 0 ==> 代表 1与0, 3与0接触 等情况
        func union(_ xPoint: Int, _ yPoint: Int) {
            let xPoint_v = find(xPoint)
            let yPoint_v = find(yPoint)
            if xPoint_v != yPoint_v {
                father[yPoint_v] = xPoint_v
            }
        }
    }
}

2024华为OD机试卷题 文章被收录于专栏

本专栏给大家提供了华为2024最新华为OD 题目汇总。华为OD机试刷题记录机考算法题库,帮助你上岸华为。提供C++/Java、JavaScript、Python四种语言的解法。

全部评论

相关推荐

1 收藏 评论
分享
牛客网
牛客企业服务