(C卷,200分)- 欢乐的周末(Java & JS & Python & C)

题目描述

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

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

输入描述

第一行输入 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。若二者可以连通,则再看每一个餐厅的祖先是否和华为的祖先相同,若相同则计数++,这样就可以得到小华,小为去的同一个餐厅的数量了。


2023.11.30 请特别注意下:

本题输入中

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

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

JavaScript算法源码

const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
  // 长度m是行数, 宽度n是列数
  const [m, n] = (await readline()).split(" ").map(Number);

  const matrix = [];
  for (let i = 0; i < m; i++) {
    matrix.push((await readline()).split(" ").map(Number));
  }

  console.log(getResult(matrix));
})();

function getResult(matrix) {
  const rows = matrix.length;
  const cols = matrix[0].length;

  const ufs = new UnionFindSet(rows * cols);

  // 记录小华,小为的位置
  const huawei = [];
  // 记录餐厅的位置
  const restrant = [];

  // 上下左右四个方向偏移量
  const offsets = [
    [-1, 0],
    [1, 0],
    [0, -1],
    [0, 1],
  ];

  for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
      if (matrix[i][j] !== 1) {
        // 二维坐标(i, j) 转为 一维坐标pos
        const pos = i * cols + j;

        if (matrix[i][j] === 2) {
          // 收集小华,小为的位置
          huawei.push(pos);
        } else if (matrix[i][j] === 3) {
          // 收集餐厅的位置
          restrant.push(pos);
        }

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

  const [hua, wei] = huawei;

  // 小华所在连通分量的根
  const hua_fa = ufs.find(hua);

  // 小为所在连通分量的根
  const wei_fa = ufs.find(wei);

  // 如果小华和小为的不属于同一个连通分量,则二人无法去往相同餐厅
  if (hua_fa !== wei_fa) {
    return 0;
  }

  // 找出和小华、小为在同一个连通分量里面的餐厅
  return restrant.filter((r) => ufs.find(r) === hua_fa).length;
}

// 并查集实现
class UnionFindSet {
  constructor(n) {
    this.fa = new Array(n).fill(0).map((_, idx) => idx);
  }

  find(x) {
    if (x !== this.fa[x]) {
      return (this.fa[x] = this.find(this.fa[x]));
    }
    return x;
  }

  union(x, y) {
    const x_fa = this.find(x);
    const y_fa = this.find(y);

    if (x_fa !== y_fa) {
      this.fa[y_fa] = x_fa;
    }
  }
}

Java算法源码

import java.util.ArrayList;
import java.util.Scanner;

public class Main {

  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);

    // 长度m表示行数
    int m = sc.nextInt();
    // 宽度n表示列数
    int n = sc.nextInt();

    int[][] matrix = new int[m][n];

    for (int i = 0; i < m; i++) {
      for (int j = 0; j < n; j++) {
        matrix[i][j] = sc.nextInt();
      }
    }

    System.out.println(getResult(matrix));
  }

  public static int getResult(int[][] matrix) {
    int rows = matrix.length;
    int cols = matrix[0].length;

    UnionFindSet ufs = new UnionFindSet(rows * cols);

    // 记录小华,小为的位置
    ArrayList<Integer> huawei = new ArrayList<>();
    // 记录餐厅的位置
    ArrayList<Integer> restaurants = new ArrayList<>();

    // 上下左右四个方向偏移量
    int[][] offsets = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

    for (int i = 0; i < rows; i++) {
      for (int j = 0; j < cols; j++) {
        if (matrix[i][j] != 1) {
          // 二维坐标(i, j) 转为 一维坐标pos
          int pos = i * cols + j;

          if (matrix[i][j] == 2) {
            // 收集小华,小为的位置
            huawei.add(pos);
          } else if (matrix[i][j] == 3) {
            // 收集餐厅的位置
            restaurants.add(pos);
          }

          for (int[] offset : offsets) {
            int newI = i + offset[0];
            int 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);
            }
          }
        }
      }
    }

    // 小华所在连通分量的根
    int hua_fa = ufs.find(huawei.get(0));
    // 小为所在连通分量的根
    int wei_fa = ufs.find(huawei.get(1));

    // 如果小华和小为的不属于同一个连通分量,则二人无法去往相同餐厅
    if (hua_fa != wei_fa) {
      return 0;
    }

    // 找出和小华、小为在同一个连通分量里面的餐厅
    int ans = 0;
    for (Integer restaurant : restaurants) {
      if (ufs.find(restaurant) == hua_fa) {
        ans++;
      }
    }

    return ans;
  }
}

// 并查集实现
class UnionFindSet {
  int[] fa;

  public UnionFindSet(int n) {
    fa = new int[n];
    for (int i = 0; i < n; i++) fa[i] = i;
  }

  public int find(int x) {
    if (x != this.fa[x]) {
      this.fa[x] = this.find(this.fa[x]);
      return this.fa[x];
    }
    return x;
  }

  public void union(int x, int y) {
    int x_fa = this.find(x);
    int y_fa = this.find(y);

    if (x_fa != y_fa) {
      this.fa[y_fa] = x_fa;
    }
  }
}

Python算法源码

# 输入获取
m, n = map(int, input().split())  # 长度m是行数, 宽度n是列数
matrix = [list(map(int, input().split())) for _ in range(m)]


# 并查集实现
class UnionFindSet:
    def __init__(self, n):
        self.fa = [i for i in range(n)]

    def find(self, x):
        if x != self.fa[x]:
            self.fa[x] = self.find(self.fa[x])
            return self.fa[x]
        return x

    def union(self, x, y):
        x_fa = self.find(x)
        y_fa = self.find(y)
        if x_fa != y_fa:
            self.fa[y_fa] = x_fa


# 算法入口
def getResult():
    rows = len(matrix)
    cols = len(matrix[0])

    ufs = UnionFindSet(rows * cols)

    #  记录小华,小为的位置
    huawei = []
    # 记录餐厅的位置
    restaurants = []
    # 上下左右四个方向偏移量
    offsets = ((-1, 0), (1, 0), (0, -1), (0, 1))

    for i in range(rows):
        for j in range(cols):
            if matrix[i][j] != 1:
                # 二维坐标(i, j) 转为 一维坐标pos
                pos = i * cols + j

                if matrix[i][j] == 2:
                    # 收集小华,小为的位置
                    huawei.append(pos)
                elif matrix[i][j] == 3:
                    # 收集餐厅的位置
                    restaurants.append(pos)

                for offset in offsets:
                    newI = i + offset[0]
                    newJ = j + offset[1]

                    if 0 <= newI < rows and 0 <= newJ < cols and matrix[newI][newJ] != 1:
                        # 如果(i,j)和(newI,newJ)位置都是非1,则合并
                        ufs.union(pos, newI * cols + newJ)

    # 小华所在连通分量的根
    hua_fa = ufs.find(huawei[0])
    # 小为所在连通分量的根
    wei_fa = ufs.find(huawei[1])

    # 如果小华和小为的不属于同一个连通分量,则二人无法去往相同餐厅
    if hua_fa != wei_fa:
        return 0

    # 找出和小华、小为在同一个连通分量里面的餐厅
    ans = 0
    for r in restaurants:
        if ufs.find(r) == hua_fa:
            ans += 1

    return ans


# 算法调用
print(getResult())

C算法源码

#include <stdio.h>
#include <stdlib.h>

/** 并查集定义 **/
typedef struct {
    int *fa;
    int count;
} UFS;

UFS *new_UFS(int n) {
    UFS *ufs = (UFS *) malloc(sizeof(UFS));

    ufs->fa = (int *) malloc(sizeof(int) * n);
    for (int i = 0; i < n; i++) {
        ufs->fa[i] = i;
    }

    ufs->count = n;

    return ufs;
}

int find_UFS(UFS *ufs, int x) {
    if (x != ufs->fa[x]) {
        ufs->fa[x] = find_UFS(ufs, ufs->fa[x]);
        return ufs->fa[x];
    }
    return x;
}

void union_UFS(UFS *ufs, int x, int y) {
    int x_fa = find_UFS(ufs, x);
    int y_fa = find_UFS(ufs, y);

    if (x_fa != y_fa) {
        ufs->fa[y_fa] = x_fa;
        ufs->count--;
    }
}

int main() {
    // 长度m表示行数, 宽度n表示列数
    int m, n;
    scanf("%d %d", &m, &n);

    int matrix[m][n];
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            scanf("%d", &matrix[i][j]);
        }
    }

    UFS *ufs = new_UFS(n * m);

    // 记录小华,小为的位置
    int huawei[2];
    int huawei_size = 0;

    // 记录餐厅的位置
    int restaurants[m * n];
    int restaurants_size = 0;

    // 上下左右四个方向偏移量
    int offsets[4][2] = {{-1, 0},
                         {1,  0},
                         {0,  -1},
                         {0,  1}};

    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if(matrix[i][j] == 1) continue;

            // 二维坐标(i, j) 转为 一维坐标pos
            int pos = i * n + j;

            switch (matrix[i][j]) {
                case 2:
                    // 收集小华,小为的位置
                    huawei[huawei_size++] = pos;
                    break;
                case 3:
                    // 收集餐厅的位置
                    restaurants[restaurants_size++] = pos;
                    break;
            }

            for (int k = 0; k < 4; k++) {
                int newI = i + offsets[k][0];
                int newJ = j + offsets[k][1];
                if (newI >= 0 && newI < m && newJ >= 0 && newJ < n && matrix[newI][newJ] != 1) {
                    // 如果(i,j)和(newI,newJ)位置都是非1,则合并
                    union_UFS(ufs, pos, newI * n + newJ);
                }
            }
        }
    }

    // 小华所在连通分量的根
    int hua_fa = find_UFS(ufs, huawei[0]);
    // 小为所在连通分量的根
    int wei_fa = find_UFS(ufs, huawei[1]);

    if (hua_fa != wei_fa) {
        // 如果小华和小为的不属于同一个连通分量,则二人无法去往相同餐厅
        puts("0");
    } else {
        // 找出和小华、小为在同一个连通分量里面的餐厅
        int ans = 0;
        for (int i = 0; i < restaurants_size; i++) {
            if (find_UFS(ufs, restaurants[i]) == hua_fa) {
                ans++;
            }
        }
        printf("%dn", ans);
    }

    return 0;
}

免责声明:

1、IT资源小站为非营利性网站,全站所有资料仅供网友个人学习使用,禁止商用
2、本站所有文档、视频、书籍等资料均由网友分享,本站只负责收集不承担任何技术及版权问题
3、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除下载链接并致以最深的歉意
4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
5、一经注册为本站会员,一律视为同意网站规定,本站管理员及版主有权禁止违规用户
6、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和IT资源小站的同意
7、IT资源小站管理员和版主有权不事先通知发贴者而删除本文

0

评论0

站点公告

没有账号?注册  忘记密码?