华为机试:学生方阵

这篇博客介绍了如何解决一个学生方阵排列的问题,目标是找到矩形方阵中最大位置相连的男生数量。文章提供了两种解法,一种是动态规划,分为四个方向分别进行;另一种是模拟法,分别讨论四种情况。每种方法都给出了详细的思路分析和参考代码,并邀请读者在评论区分享更简洁的算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【编程题目 |200分】学生方阵【2022 Q2 考试题】

题目描述
  • 学校组织活动,将学生排成一个矩形方阵。
  • 请在矩形方阵中找到最大的位置相连的男生数量。
  • 这个相连位置在一个直线上,方向可以是水平的,垂直的,成对角线的或者呈反对角线的。
  • 注:学生个数不会超过10000
输入描述
  • 输入的第一行为矩阵的行数和列数,接下来的n行为矩阵元素,元素间用”,”分隔。
输出描述
  • 输出一个整数,表示矩阵中最长的位置相连的男生个数。
示例
输入
3,4
F,M,M,F
F,M,M,F
F,F,F,M
输出
3
输入
1,2
M,M
输出
2
输入
2,1
M
F
输出
1
思路分析

方法一:动态规划

这道题看到方阵,下一个格子跟上一个格子有关系,横着、竖着、对角线、反对角线,可以想到动态规划的解法。

不过需要注意的是,四种情况要分开考虑,分别进行动态规划:

  1. 初始化第一行和第一列,往右下角找,就可以统计横着,竖着,对角线的最大值。
  2. 初始化第一行,最后一列,往左下角找,就可以统计反对角线的最大值。

如果整体动态规划,则横着的会影响竖着的,比如

3,4
F,M,M,F
F,M,M,F
F,F,F,F

如果直接整体动态规划,会受到干扰,会出现重复加的情况

dp[i][j] = Math.max(dp[i - 1][j], Math.max(dp[i][j - 1), dp[i - 1][j - 1]) + 1;

所以需要分开四个方向分别进行动态规划,最后再计算四个方向的最大值。

还有一点需要注意的是,在初始化数组的时候,如果对第一行,第一列,或者最后一列,遇到"M",初始化为1时,当只有一行或一列的情况,则不会统计,因此需要对特殊情况,一行或一列的单独进行处理。

方法二:模拟

分别讨论这四种情况下的最长数量。

参考代码

方法一:动态规划

import java.util.Scanner;
public class studentFangZhen {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String[] str1 = in.nextLine().split(",");
        int m = Integer.parseInt(str1[0]);
        int n = Integer.parseInt(str1[1]);
        String[][] s = new String[m][n];
        for (int i = 0; i < m; i++) {
            String[] s1 = in.nextLine().split(",");
            for (int j = 0; j < n; j++) {
                s[i][j] = s1[j];
            }
        }
        int[][] dp1 = new int[m][n];  // 从左往右
        int[][] dp2 = new int[m][n];  // 从上往下
        int[][] dp3 = new int[m][n];  // 对角线
        int[][] dp4 = new int[m][n];  // 反对角线
        // 特例,只有一行或只有一列,不能给每一个等于M的初始化为1,还要考虑前一个的情况
        int ans = 0;
        if (m == 1) {
            if (s[0][0].equals("M")) {
                dp1[0][0] = 1;
            }
            for (int j = 1; j < n; j++) {
                if (s[0][j - 1].equals("M")) {
                    if (s[0][j].equals("M")) {
                        dp1[0][j] = dp1[0][j - 1] + 1;
                    }
                } else {
                    if (s[0][j].equals("M")){
                        dp1[0][j] = 1;
                    }
                }
            }
            for (int j = 0; j < n; j++) {
                ans = Math.max(ans, dp1[0][j]);
            }
            System.out.println(ans);
            return;
        }
        if (n == 1) {
            if (s[0][0].equals("M")) {
                dp2[0][0] = 1;
            }
            for (int i = 1; i < m; i++) {
                if (s[i - 1][0].equals("M")) {
                    if (s[i][0].equals("M")) {
                        dp2[i][0] = dp2[i - 1][0] + 1;
                    }
                } else {
                    if (s[i][0].equals("M")) {
                        dp2[i][0] = 1;
                    }
                }
            }
            for (int i = 0; i < m; i++) {
                ans = Math.max(ans, dp2[i][0]);
            }
            System.out.println(ans);
            return;
        }
        // 初始化dp1, dp2, dp3, dp4数组
        for (int i = 0; i < m; i++) {
            if (s[i][0].equals("M")) {
                dp1[i][0] = 1;
                dp2[i][0] = 1;
                dp3[i][0] = 1;
            }
        }
        for (int j = 0; j < n; j++) {
            if (s[0][j].equals("M")) {
                dp1[0][j] = 1;
                dp2[0][j] = 1;
                dp3[0][j] = 1;
                dp4[0][j] = 1;
            }
        }
        // 初始化dp4数组
        for (int i = 0; i < m; i++) {
            if (s[i][n - 1].equals("M")) {
                dp4[i][n - 1] = 1;
            }
        }
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                if (s[i][j].equals("M")) {
                    if (s[i][j - 1].equals("M")) { // 从左往右
                        dp1[i][j] = dp1[i][j - 1] + 1;
                    }
                    if (s[i - 1][j].equals("M")) {  // 从上往下
                        dp2[i][j] = dp2[i - 1][j] + 1;
                    }
                    if (s[i - 1][j - 1].equals("M")) { // 对角线
                        dp3[i][j] = dp3[i - 1][j - 1] + 1;
                    }
                }
            }
        }
        for (int i = 1; i < m; i++) {
            for (int j = n - 2; j >= 0; j--) {
                if (s[i][j].equals("M")) {
                    if (s[i - 1][j + 1].equals("M")) { // 反对角线
                        dp4[i][j] = dp4[i - 1][j + 1] + 1;
                    }
                }
            }
        }
        for (int i = 0; i < m; i++) {  // 取四个数组中的最大值
            for (int j = 0; j < n; j++) {
                ans = Math.max(ans, Math.max(dp1[i][j], Math.max(dp2[i][j], Math.max(dp3[i][j], dp4[i][j]))));
            }
        }
        System.out.println(ans);
    }
}

这样写下来比较复杂,欢迎在评论区讨论以及留下更简单的算法。

方法二:模拟

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;

public class StudentFangZhen2 {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String[] str1 = in.nextLine().split(",");
        int m = Integer.parseInt(str1[0]);
        int n = Integer.parseInt(str1[1]);
        String[][] s = new String[m][n];
        for (int i = 0; i < m; i++) {
            String[] s1 = in.nextLine().split(",");
            for (int j = 0; j < n; j++) {
                s[i][j] = s1[j];
            }
        }
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (s[i][j].equals("M")) {
                    getResult(s, i, j, list);
                }
            }
        }
        Collections.sort(list);
        System.out.println(list.get(list.size() - 1));
    }
    public static void getResult(String[][] s, int i, int j, List<Integer> list) {
        int len = 1;
        int a = 0, b = 0;
        int m = s.length, n = s[0].length;
        if (j < n) {  // 从左往右
            a = i;
            b = j;
            while (b < n - 1 && s[a][++b].equals("M")) {
                len++;
            }
            list.add(len);
            len = 1;
        }
        if (i < m) {  // 从上往下
            a = i;
            b = j;
            while (a < m - 1 && s[++a][b].equals("M")) {
                len++;
            }
            list.add(len);
            len = 1;
        }
        if (i < m && j < n) {  // 对角线
            a = i;
            b = j;
            while ((a < m - 1 && b < n - 1) && s[++a][++b].equals("M")) {
                len++;
            }
            list.add(len);
            len = 1;
        }
        if (i >= 0 && j < n) {  // 从左往右
            a = i;
            b = j;
            while (( a > 0 && b < n - 1) && s[--a][++b].equals("M")) {
                len++;
            }
            list.add(len);
        }
    }
}

欢迎在评论区指正以及留下自己的更简洁的方法。

### 华为 OD 模式下的学生方阵项目介绍 #### 1. 题目背景与目标 华为OD中的“学生方阵”题目旨在测开发者的算法设计能力,特别是针对矩阵遍历和深度优先搜索(DFS)的应用场景。该问题的核心在于寻找给定二维矩阵中连续相连的最大男性人数[^1]。 #### 2. 输入与输出说明 输入数据由两部分组成:首先是两个正整数 n 和 m (n,m ≤ 100),分别代表矩阵的行数和列数;随后是 n 行字符串,每行为长度等于 m 的字符序列,其中 'F' 表示女性,而 'M' 则表示男性[^3]。 程序需返回一个整数值作为结果,即矩阵中最长的位置相连的男性数量[^4]。 #### 3. 连接规则解释 连接的方向不仅限于上下左右四个基本方位,还包括斜向上的左上方、右上方以及下方对应的左下方、右下方共八个可能方向。这意味着当评估某个特定单元格时,应考虑其周围八邻域内的所有潜在关联节点来判断是否存在更长链路的可能性。 #### 4. 实现方法概述 解决此问题通常采用递归形式实现的 DFS 方法来进行探索。具体步骤如下所示: - **初始化访问标记数组**:创建大小相同的布尔型辅助数组用于记录哪些位置已被探查过。 - **定义移动操作集合**:构建包含上述提到的所有8种位移方式的数据结构以便后续迭代使用。 - **执行深搜过程**:对于每一个尚未被触及且属于男性的网格点启动一次新的搜索流程,在过程中不断累加计数值直至无法继续扩展为止。 - **维护全局最优解变量**:在整个遍历期间持续跟踪并保存发现的最大连通区域规模。 以下是基于Python语言的一个简单示范版本: ```python def max_connected_males(matrix): if not matrix or not matrix[0]: return 0 rows, cols = len(matrix), len(matrix[0]) visited = [[False]*cols for _ in range(rows)] directions = [ (-1,-1),(0,-1),(1,-1), (-1, 0), (1, 0), (-1, 1),(0, 1),(1, 1) ] def dfs(r,c): stack = [(r,c)] count = 0 while stack: x,y = stack.pop() if 0<=x<rows and 0<=y<cols and not visited[x][y] and matrix[x][y]=='M': visited[x][y]=True count +=1 for dx,dy in directions: nx,ny=x+dx,y+dy if 0<=nx<rows and 0<=ny<cols and not visited[nx][ny]: stack.append((nx, ny)) return count result=0 for r in range(rows): for c in range(cols): if matrix[r][c]=='M'and not visited[r][c]: current_max=dfs(r,c) result=max(result,current_max) return result # Example Usage matrix=[ ["F","M","M","F"], ["F","M","M","F"], ["F","F","F","M"] ] print(max_connected_males(matrix)) # Output should be 3 according to provided example. ``` 以上代码片段展示了如何利用栈模拟非递归版的DFS逻辑去处理这个问题实例[^5]。 #### 5. 性能考量 由于最大矩阵尺寸限定较小(n*m≤1e4),因此即使采用了较为朴素的时间复杂度O(N*M)级别的解决方案也能满足实际需求。然而为了进一步优化性能表现,还可以尝引入更多高级技巧比如记忆化存储中间状态减少重复计算次数等等[^2]。 ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值