华为OD笔试机试 - 反射计数 (python/c++/java 2024年C卷D卷真题算法)

华为OD机试(C卷+D卷)2024真题目录(Java & c++ & python)

题目描述

给定一个包含 0 和 1 的二维矩阵。

给定一个初始位置和速度,一个物体从给定的初始位置出发,在给定的速度下进行移动,遇到矩阵的边缘则发生镜面发射。

无论物体经过 0 还是 1,都不影响其速度。

请计算并给出经过 t 时间单位后,物体经过 1 点的次数。

矩阵以左上角位置为 [0, 0](列(x),行(y)),例如下面A点坐标为 [2, 1](第二列,第一行)
在这里插入图片描述

注意:

  • 如果初始位置的点是 1,也计算在内
  • 时间的最小单位为 1,不考虑小于 1 个时间单位内经过的点

输入描述

第一行为初始信息

<w><h><x><y><sx><sy><t>

第二行开始一共 h 行,为二维矩阵信息

其中:

  • w,h 为矩阵的宽和高
  • x,y 为起始位置
  • sx,sy 为初始速度
  • t 为经过的时间

所有输入都是有效的,数据范围如下:

  • 0 < w < 100
  • 0 < h < 100
  • 0 ≤ x < w
  • 0 ≤ y < h
  • -1 ≤ sx ≤ 1
  • -1 ≤ sy ≤ 1
  • 0 ≤ t <100

输出描述

经过 1 的个数

注意初始位置也要计算在内

用例

输入

12 7 2 1 1 -1 13
001000010000
001000010000
001000010000
001000010000
001000010000
001000010000
001000010000

输出

3

说明
初始位置为(2,1),速度为(1,-1),那么13个时间单位后,经过点1的个数为3
在这里插入图片描述

解题思路

在这里插入图片描述
如果当前位置 x,y 按照速度 sx,sy 运动后,新位置越界的话,比如新位置x,y:

  • x < 0
    注意 -1 ≤ sx, sy ≤ 1,因此 x < 0 越界时必然 x = -1, 则经过反射,x = 1
  • x >= w
    注意 -1 ≤ sx, sy ≤ 1,因此 x >= w 越界时必然 x = w, 则经过反射,x = w - 2
  • y < 0
    注意 -1 ≤ sx, sy ≤ 1,因此 y < 0 越界时必然 y = -1,则经过反射,y = 1
  • y >= h
    注意 -1 ≤ sx, sy ≤ 1,因此 y >= h 越界时必然 y = h,则经过反射,y = h - 2

还需要注意的是,反射不仅会影响位置,而且会影响和后续的速度方向:

  • 一旦新位置x越界,则后续速度 sx = -sx
  • 一旦新位置y越界,则后续速度 sy = -sy

我们只要记录运动路径中遇到的元素1的个数即可。

C++、Java、Python代码如下:

C++参考代码

#include <bits/stdc++.h>
using namespace std;

int main() {
    int w, h, x, y, sx, sy, t;
    cin >> w >> h >> x >> y >> sx >> sy >> t;

    // 输入矩阵
    string matrix[h];
    for (int i = 0; i < h; i++) {
        cin >> matrix[i];
    }

    int ans = 0;

    while (t >= 0) {
        // 注意本题横纵坐标是反的,因此y其实是行号,x是列号
        if (matrix[y][x] == '1') {
            ans++;
        }

        // 更新位置
        y += sy;
        x += sx;

        // 处理 x 方向的反弹
        if (x < 0) {
            x = 1;       // 反弹后位置为第二列
            sx = -sx;    // 水平方向速度反转
        } else if (x >= w) { 
            x = w - 2;   // 反弹后位置为倒数第二列
            sx = -sx;    // 水平方向速度反转
        }

        // 处理 y 方向的反弹
        if (y < 0) {
            y = 1;       // 反弹后位置为第二行
            sy = -sy;    // 垂直方向速度反转
        } else if (y >= h) { 
            y = h - 2;   // 反弹后位置为倒数第二行
            sy = -sy;    // 垂直方向速度反转
        }

        t--; // 时间递减
    }

    cout << ans << endl; // 输出经过 '1' 的格子数

    return 0;
}

Java参考代码

import java.util.Scanner;
 
public class Main {
 
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    
    // 输入参数
    int w = sc.nextInt();  // 矩阵的宽度
    int h = sc.nextInt();  // 矩阵的高度
    int x = sc.nextInt();  // 起始位置的 x 坐标(列)
    int y = sc.nextInt();  // 起始位置的 y 坐标(行)
    int sx = sc.nextInt(); // 水平速度
    int sy = sc.nextInt(); // 垂直速度
    int t = sc.nextInt();  // 总时间

    // 读取矩阵
    char[][] matrix = new char[h][w];
    for (int i = 0; i < h; i++) {
      matrix[i] = sc.next().toCharArray();  // 每一行输入转换为字符数组
    }
 
    int ans = 0;  // 统计经过标记为 '1' 的格子的次数
 
    while (t >= 0) {
      // 注意:y 是行号,x 是列号
      if (matrix[y][x] == '1') {
        ans++;
      }
 
      // 更新物体位置
      y += sy;
      x += sx;
 
      // 处理 x 方向的边界反弹
      if (x < 0) {
        x = 1;         // 反弹后的位置
        sx = -sx;      // 反转水平速度
      } else if (x >= w) { // 当超出右边界
        x = w - 2;     // 反弹后的位置
        sx = -sx;      // 反转水平速度
      }
 
      // 处理 y 方向的边界反弹
      if (y < 0) {
        y = 1;         // 反弹后的位置
        sy = -sy;      // 反转垂直速度
      } else if (y >= h) { // 当超出下边界
        y = h - 2;     // 反弹后的位置
        sy = -sy;      // 反转垂直速度
      }
 
      t--;  // 时间递减
    }
 
    // 输出经过标记为 '1' 的格子的次数
    System.out.println(ans);
  }
}

Python参考代码

# 输入获取
w, h, x, y, sx, sy, t = map(int, input().split())
matrix = [input() for _ in range(h)]

ans = 0

while t >= 0:
    # 注意本题横纵坐标是反的,因此y其实是行号,x是列号
    if matrix[y][x] == '1':
        ans += 1

    y += sy
    x += sx

    if x < 0:
        x = 1
        sx = -sx
    elif x >= w:  # 注意本题横纵坐标是反的,因此x是列号,w是矩阵列数
        x = w - 2
        sx = -sx

    if y < 0:
        y = 1
        sy = -sy
    elif y >= h:  # 注意本题横纵坐标是反的,因此y是行号,h是矩阵行数
        y = h - 2
        sy = -sy

    t -= 1

print(ans)

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

算法之旅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值