【Py/Java/C++三种语言OD独家2024D卷真题】20天拿下华为OD笔试之【DFS/BFS】2024D-可以组成网络的服务器【欧弟算法】全网注释最详细分类最全的华为OD真题题解

40 篇文章 1 订阅
38 篇文章 1 订阅

有LeetCode算法/华为OD考试扣扣交流群可加 948025485
可上全网独家的 欧弟OJ系统 练习华子OD、大厂真题
绿色聊天软件戳 od1441了解算法冲刺训练(备注【CSDN】否则不通过)

从2024年4月15号开始,OD机考全部配置为2024D卷
注意两个关键点:

  1. 会遇到C卷复用题。虽然可能存在幸存者偏差,但肯定还会有一大部分的旧题。
  2. 现在又支持做完题目之后倒回去改了。就是可以先做200的再做100的,然后可以反复提交。
    在这里插入图片描述

题目描述与示例

题目描述

在一个机房中,服务器的位置标识在 n*m 的整数矩阵网格中,1表示单元格上有服务器,0 表示没有。如果两台服务器位于同一行或者同一列中紧邻的位置,则认为它们之间可以组成一个局域网。请你统计机房中最大的局域网包含的服务器个数。

输入描述

第一行输入两个正整数,nm0 < n,m <= 100

之后为n*m的二维数组,代表服务器信息

输出描述

最大局域网包含的服务器个数。

示例

输入

2 2
1 0
1 1

输出

3

补充说明

[0][0][1][0][1][1]三台服务器相互连接,可以组成局域网

解题思路

注意,本题和LeetCode695、岛屿的最大面积 完全一致,直接套模板即可。

代码

解法一:DFS

python

# 题目:2023C-可以组成网络的服务器
# 分值:200
# 作者:闭着眼睛学数理化
# 算法:DFS
# 代码看不懂的地方,请直接在群上提问

import sys
sys.setrecursionlimit(10000)

# 初始化上下左右四个方向的数组
DERICTIONS = [(0,1), (1,0), (0,-1), (-1,0)]

# 构建DFS函数
def DFS(grid, i, j, checkList):
    global area
    # 将该点标记为已经检查过
    checkList[i][j] = True
    # 面积增大
    area += 1
    # 遍历上下左右四个方向的邻点坐标
    for dx, dy in DERICTIONS:
        next_i, next_j = i + dx, j + dy
        # 若近邻点满足三个条件:
        # 1.没有越界    2. 近邻点尚未被检查过   3.近邻点也为陆地
        if ((0 <= next_i < n and 0 <= next_j < m) and checkList[next_i][next_j] == False
            and grid[next_i][next_j] == 1):
            # 对近邻点(ni, nj)进行DFS搜索
            DFS(grid, next_i, next_j, checkList)


# 输入长、宽
n, m = map(int, input().split())
# 构建网格
grid = list()
for _ in range(n):
    grid.append(list(map(int, input().split())))

ans = 0
# 初始化数组checkList用于DFS遍历过程中的检查
# 0表示尚未访问,1表示已经访问
checkList = [[False] * m for _ in range(n)]

# 对整个grid二维数组进行双重循环遍历
for i in range(n):
    for j in range(m):
        # 若该点为陆地且还没有进行过搜寻
        if grid[i][j] == 1 and checkList[i][j] == False:
            # 在每一次DFS之前,先初始化面积为0
            area = 0
            # 可以进行DFS
            DFS(grid, i, j, checkList)
            # 做完DFS,更新ans
            ans = max(ans, area)

print(ans)

java

import java.util.Scanner;

public class Main {
    static final int[][] DIRECTIONS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    static int n, m;
    static int[][] grid;
    static boolean[][] checkList;
    static int area;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();
        m = scanner.nextInt();
        grid = new int[n][m];
        checkList = new boolean[n][m];

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

        int ans = 0;

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 1 && !checkList[i][j]) {
                    area = 0;
                    DFS(i, j);
                    ans = Math.max(ans, area);
                }
            }
        }

        System.out.println(ans);
    }

    static void DFS(int i, int j) {
        checkList[i][j] = true;
        area++;

        for (int[] dir : DIRECTIONS) {
            int nextI = i + dir[0];
            int nextJ = j + dir[1];
            if (isValid(nextI, nextJ) && !checkList[nextI][nextJ] && grid[nextI][nextJ] == 1) {
                DFS(nextI, nextJ);
            }
        }
    }

    static boolean isValid(int i, int j) {
        return i >= 0 && i < n && j >= 0 && j < m;
    }
}

cpp

#include <iostream>
#include <vector>

using namespace std;

vector<pair<int, int>> DIRECTIONS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
int n, m;
vector<vector<int>> grid;
vector<vector<bool>> checkList;
int area;

void DFS(int i, int j) {
    checkList[i][j] = true;
    area++;

    for (auto dir : DIRECTIONS) {
        int nextI = i + dir.first;
        int nextJ = j + dir.second;
        if (nextI >= 0 && nextI < n && nextJ >= 0 && nextJ < m && !checkList[nextI][nextJ] && grid[nextI][nextJ] == 1) {
            DFS(nextI, nextJ);
        }
    }
}

int main() {
    cin >> n >> m;
    grid.resize(n, vector<int>(m));
    checkList.resize(n, vector<bool>(m, false));

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> grid[i][j];
        }
    }

    int ans = 0;

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (grid[i][j] == 1 && !checkList[i][j]) {
                area = 0;
                DFS(i, j);
                ans = max(ans, area);
            }
        }
    }

    cout << ans << endl;

    return 0;
}

解法二:BFS

python

# 题目:2023C-可以组成网络的服务器
# 分值:200
# 作者:闭着眼睛学数理化
# 算法:BFS
# 代码看不懂的地方,请直接在群上提问


from collections import deque

# 初始化上下左右四个方向的数组
DIRECTIONS = [(0,1), (1,0), (0,-1), (-1,0)]

# 输入长、宽
n, m = map(int, input().split())
# 构建网格
grid = list()
for _ in range(n):
    grid.append(list(map(int, input().split())))
    
ans = 0                                      
# 初始化和grid一样大小的二维数组checkList用于DFS遍历过程中的检查
checkList = [[0] * m for _ in range(n)]
# 双重遍历grid数组
for i in range(n):
    for j in range(m):
        # 若该点为1且还没有进行过搜寻
        # 找到了一个BFS搜索的起始位置(i,j)
        if grid[i][j] == 1 and checkList[i][j] == 0:
            # 对于该片连通块,构建一个队列,初始化包含该点
            q = deque()
            q.append((i, j))
            # 修改checkList[i][j]为1,表示该点已经搜寻过
            checkList[i][j] = 1
            # 进行BFS之前,初始化该连通块的面积为0
            area = 0
            # 进行BFS,退出循环的条件是队列为空
            while len(q) > 0:
                # 弹出栈队头的点(x,y) 搜寻该点上下左右的近邻点
                x, y = q.popleft()
                area += 1
                # 遍历(x,y)上下左右的四个方向的近邻点
                for dx, dy in DIRECTIONS:
                    x_next, y_next = x+dx, y+dy
                    # 如果近邻点满足三个条件
                    if (0 <= x_next < n and 0 <= y_next < m and checkList[x_next][y_next] == 0
                            and grid[x_next][y_next] == 1):
                            # 对近邻点做两件事:
                            # 1. 入队       2. 标记为已检查过
                            q.append((x_next, y_next))
                            checkList[x_next][y_next] = 1
            # 更新答案
            ans = max(ans, area)
print(ans)

java

import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Scanner;

public class Main {
    static final int[][] DIRECTIONS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();

        int[][] grid = new int[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                grid[i][j] = scanner.nextInt();
            }
        }

        int ans = 0;
        int[][] checkList = new int[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] == 1 && checkList[i][j] == 0) {
                    Queue<int[]> queue = new ArrayDeque<>();
                    queue.offer(new int[]{i, j});
                    checkList[i][j] = 1;
                    int area = 0;

                    while (!queue.isEmpty()) {
                        int[] point = queue.poll();
                        int x = point[0];
                        int y = point[1];
                        area++;

                        for (int[] dir : DIRECTIONS) {
                            int xNext = x + dir[0];
                            int yNext = y + dir[1];
                            if (xNext >= 0 && xNext < n && yNext >= 0 && yNext < m
                                    && checkList[xNext][yNext] == 0 && grid[xNext][yNext] == 1) {
                                queue.offer(new int[]{xNext, yNext});
                                checkList[xNext][yNext] = 1;
                            }
                        }
                    }

                    ans = Math.max(ans, area);
                }
            }
        }

        System.out.println(ans);
    }
}

cpp

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

vector<pair<int, int>> DIRECTIONS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

int main() {
    int n, m;
    cin >> n >> m;
    
    vector<vector<int>> grid(n, vector<int>(m));
    vector<vector<int>> checkList(n, vector<int>(m, 0));
    
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            cin >> grid[i][j];
        }
    }
    
    int ans = 0;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            if (grid[i][j] == 1 && checkList[i][j] == 0) {
                queue<pair<int, int>> q;
                q.push({i, j});
                checkList[i][j] = 1;
                int area = 0;
                while (!q.empty()) {
                    int x = q.front().first;
                    int y = q.front().second;
                    q.pop();
                    area++;
                    for (auto dir : DIRECTIONS) {
                        int x_next = x + dir.first;
                        int y_next = y + dir.second;
                        if (x_next >= 0 && x_next < n && y_next >= 0 && y_next < m &&
                            checkList[x_next][y_next] == 0 && grid[x_next][y_next] == 1) {
                            q.push({x_next, y_next});
                            checkList[x_next][y_next] = 1;
                        }
                    }
                }
                ans = max(ans, area);
            }
        }
    }
    
    cout << ans << endl;
    
    return 0;
}

时空复杂度

时间复杂度:O(NM)

空间复杂度:O(NM)


华为OD算法/大厂面试高频题算法练习冲刺训练

  • 华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务300+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁

  • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

  • 可查看链接 大厂真题汇总 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 od1336了解更多

  • 15
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述 给定一个无向图,把图的结点分成两组,要求相同组内的结点之间没有连边,求这样分组的可能方案数。 输入格式 第一行一个整数 n,表示图的结点数。 接下来有 n 行,其中第 i 行的第 j 个整数表示结点 i 和结点 j 之间是否有连边。 输出格式 输出一个整数,为方案数。 输入样例 4 0 1 1 1 1 0 1 0 1 1 0 1 1 0 1 0 输出样例 10 解题思路 本题解法很多,以下介绍两种较常见的做法。 做法一:二分图染色 将整个无向图按照二分图划分为两部分,其中每一部分内的节点都没有互相连通的边。即,将图中的每个节点分为两组,使得每组内没有连边,此时的分组情况可以确定,方案数为 2^(n/2)。这里可以使用 DFSBFS 实现,需要注意以下两个细节: - 图不一定联通,因此需要对所有的节点进行遍历; - 一个无向图不一定是二分图,因此需要处理在原图中连通的节点被划分在同一组的情形。 代码如下: Java版: import java.util.*; public class Main { static int n; static int[][] w; static int[] color; public static void main(String[] args) { Scanner sc = new Scanner(System.in); n = sc.nextInt(); w = new int[n][n]; color = new int[n]; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) w[i][j] = sc.nextInt(); dfs(0, 1); int ans = 1; for (int c : color) { if (c == 0) ans *= 2; } System.out.println(ans); } static void dfs(int u, int c) { color[u] = c; for (int v = 0; v < n; v++) { if (w[u][v] == 0) continue; if (color[v] == 0) { dfs(v, 3 - c); // 如果是颜色1,则下一次染成颜色2;如果是颜色2,下一次染成颜色1 } else if (color[v] == c) { System.out.println(0); // 相邻节点颜色相同,说明不是二分图 System.exit(0); // 必须结束程序 } } } } Python版: n = int(input()) w = [list(map(int, input().split())) for _ in range(n)] color = [0] * n # color 记录染色信息,初始值为0 def dfs(u, c): color[u] = c for v in range(n): if w[u][v] == 0: continue if color[v] == 0: dfs(v, 3 - c) elif color[v] == c: print(0) exit() dfs(0, 1) ans = 1 for c in color: if c == 0: ans *= 2 print(ans) 做法二:矩阵树定理 矩阵树定理可以用于计算无向图的生成树个数以及最小割的计算。这里只介绍如何使用矩阵树定理计算无向图的染色数。 定义行列式的值为图的邻接矩阵去掉一行一列之后的行列式的值,即 d = |(W)ij|,其中 W 表示邻接矩阵。则生成树个数等于 d^(n-2)。 如果将邻接矩阵 W 的每一行都减去该行的最后一个元素,并将对角线顶点连接起来,形成的新矩阵可以用于计算染色数。新矩阵记作 M,其中 M 的 i 行表示第 i 个结点都和哪些结点相连,例如 M 的第 i 行为 [0, 1, 1, 1],表示 1、2、3 这三个结点和 i 相连。 将 M 的第 i 行中的每个元素变成该行所有数的相反数,再将对角线顶点连接起来,形成的新矩阵记作 K,那么 K 的行列式值即为答案。例如,如果 M 的第 i 行为 [0, 1, 1, 1],那么 K 矩阵的该行为 [-3, 1, 1, 1]。 代码如下: Java版: import java.util.*; public class Main { static int n; static int[][] w; static int[][] m; public static void main(String[] args) { Scanner sc = new Scanner(System.in); n = sc.nextInt(); w = new int[n][n]; m = new int[n - 1][n - 1]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { w[i][j] = sc.nextInt(); if (i != j && w[i][j] != 0) { m[Math.min(i, j)][Math.max(i, j)] = -1; } } } for (int i = 0; i < n - 1; i++) m[i][i] -= Arrays.stream(m[i]).sum(); System.out.println(det()); } static long det() { long ans = 1; for (int i = 0; i < n - 2; i++) { for (int j = i + 1; j < n - 1; j++) { while (m[j][i] != 0) { long t = m[i][i] / m[j][i]; for (int k = i; k < n - 1; k++) m[i][k] -= t * m[j][k]; for (int k = i; k < n - 1; k++) m[i][k] ^= m[j][k] ^= m[i][k] ^= m[j][k]; ans = -ans; } } ans *= m[i][i]; } return ans; } } Python版: n = int(input()) w = [list(map(int, input().split())) for _ in range(n)] m = [[0] * (n - 1) for _ in range(n - 1)] for i in range(n): for j in range(i + 1, n): if w[i][j] == 1: m[min(i, j)][max(i, j) - 1] = -1 for i in range(n - 1): m[i][i] = sum(m[i]) - m[i][i] def det(): ans = 1 for i in range(n - 2): for j in range(i + 1, n - 1): while m[j][i]: t = m[i][i] // m[j][i] for k in range(i, n - 1): m[i][k] -= t * m[j][k] m[i], m[j] = m[j], m[i] ans = -ans ans *= m[i][i] return ans print(det())

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值