华为OD机试真题 - 矩阵匹配 - 深度优先搜索DFS(Python/JS/C/C++ 2024 D卷 200分)

在这里插入图片描述

华为OD机试 2024E卷题库疯狂收录中,刷题点这里

专栏导读

本专栏收录于《华为OD机试真题(Python/JS/C/C++)》

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

一、题目描述

从一个 N×M(N≤M)的矩阵中选出 N 个数,任意两个数字不能在同一行或同一列,求选出来的 N 个数中第 K 大的数字的最小值是多少。

二、输入描述

输入矩阵要求: 1≤K≤N≤M≤150

输入格式:

N M K
N*M矩阵

三、输出描述

N×M 的矩阵中可以选出 M!/N!种组合数组,每个组合数组种第 K 大的数中的最小值。无需考虑重复数字,直接取字典排序结果即可。

备注:

注意:结果是第 K 大的数字的最小值

四、测试用例

测试用例1:

1、输入

3 3 2
2 1 4
5 3 7
9 6 8

2、输出

3

测试用例2:

1、输入

3 4 2
1 5 6 6
8 3 4 3
6 8 6 3

2、输出

3

3、说明

第一行:[2, 3, 4],第2大的数是3
第二行:[1, 5, 6, 6],第2大的数是6
第三行:[3, 3, 4, 8],第2大的数是4
第四行:[3, 6, 6, 8],第2大的数是6

所有行的第2大数中的最小值是3。

输出:3

五、解题思路

1、深度优先搜索DFS

深度优先搜索(Depth-First Search, DFS)是一种用于遍历或搜索图或树结构的算法。DFS算法从一个起始节点开始,沿着某一路径尽可能深入到一个分支的底部,然后回溯并继续探索其他分支,直到所有节点都被访问过。

DFS的核心思想是尽可能深地搜索树或图的分支,直到遇到已访问的节点或没有未访问的邻接节点为止,然后回溯到上一个节点继续搜索。

2、为什么采用深度优先搜索DFS?

在这个问题中,我们需要从一个矩阵中选择一定数量的元素,这些元素必须满足不在同一行或同一列的限制条件,同时还要找到这些元素中第 K 大的元素的最小值。这种问题的关键在于需要系统地探索所有可能的选择组合,并检查每个组合是否满足特定的条件。

DFS算法通过递归的方式深入搜索,能够遍历所有可能的选择组合。在这个问题中,DFS可以从每个矩阵元素开始,尝试选择下一个元素时递归地检查不同行不同列的约束,直到选择到足够数量的元素为止。这种方法确保不会遗漏任何一个可能的组合。

3、具体步骤:

对于给定的矩阵和选择的数量 K,问题要求从矩阵中选择 K 个数字,这些数字不能位于同一行或同一列,然后找出所有可能组合中第 K 大的数字的最小值。解题的主要步骤如下:

  1. 读取输入数据:
    • 获取矩阵的行数 N、列数 M 和需要选择的数量 K。
    • 读取 N*M 的矩阵数据。
  2. 选择组合:
    • 使用DFS进行深度优先搜索,选择矩阵中的 K 个元素。
    • 在每次选择时,确保选定的数字不在已选数字的行和列中。
  3. 计算组合中第 K 大的数字:
    • 对于每个有效的选择组合,排序并找到该组合中的第 K 大数字。
  4. 记录最小值:
    • 记录所有组合中第 K 大的数字,最终取这些数字中的最小值作为结果。
  5. 输出结果:
    • 输出最小的第 K 大数字。

六、Python算法源码

def main():
    # 读取输入
    N = int(input())
    M = int(input())
    K = int(input())
    matrix = []

    for _ in range(N):
        matrix.append(list(map(int, input().split())))

    # 存储每个组合的第K大的最小值
    min_kth_values = []

    # 从矩阵中选择 K 个数字
    select_numbers(matrix, N, M, K, [], min_kth_values)

    # 找到所有组合中的第 K 大的最小值
    result = min(min_kth_values)
    print(result)

def select_numbers(matrix, N, M, K, current_selection, min_kth_values):
    if len(current_selection) == K:
        # 对于每个选择,找到第 K 大的值
        current_selection.sort()
        min_kth_values.append(current_selection[K - 1])
        return

    for i in range(N):
        for j in range(M):
            if can_be_selected(i, j, current_selection, matrix, N, M):
                current_selection.append(matrix[i][j])
                select_numbers(matrix, N, M, K, current_selection, min_kth_values)
                current_selection.pop()

def can_be_selected(row, col, current_selection, matrix, N, M):
    # 检查行列约束
    for num in current_selection:
        position = find_position(num, matrix, N, M)
        if position[0] == row or position[1] == col:
            return False
    return True

def find_position(num, matrix, N, M):
    for i in range(N):
        for j in range(M):
            if matrix[i][j] == num:
                return (i, j)
    return (-1, -1)  # 不会发生

if __name__ == "__main__":
    main()

七、JavaScript算法源码

function main() {
    const fs = require('fs');
    const input = fs.readFileSync('/dev/stdin', 'utf8').trim().split('\n');
    
    const N = parseInt(input[0]);
    const M = parseInt(input[1]);
    const K = parseInt(input[2]);
    const matrix = [];

    for (let i = 0; i < N; i++) {
        matrix.push(input[3 + i].split(' ').map(Number));
    }

    // 存储每个组合的第K大的最小值
    const minKthValues = [];

    // 从矩阵中选择 K 个数字
    selectNumbers(matrix, N, M, K, [], minKthValues);

    // 找到所有组合中的第 K 大的最小值
    const result = Math.min(...minKthValues);
    console.log(result);
}

function selectNumbers(matrix, N, M, K, currentSelection, minKthValues) {
    if (currentSelection.length === K) {
        // 对于每个选择,找到第 K 大的值
        currentSelection.sort((a, b) => a - b);
        minKthValues.push(currentSelection[K - 1]);
        return;
    }

    for (let i = 0; i < N; i++) {
        for (let j = 0; j < M; j++) {
            if (canBeSelected(i, j, currentSelection, matrix, N, M)) {
                currentSelection.push(matrix[i][j]);
                selectNumbers(matrix, N, M, K, currentSelection, minKthValues);
                currentSelection.pop();
            }
        }
    }
}

function canBeSelected(row, col, currentSelection, matrix, N, M) {
    // 检查行列约束
    for (let num of currentSelection) {
        const position = findPosition(num, matrix, N, M);
        if (position[0] === row || position[1] === col) {
            return false;
        }
    }
    return true;
}

function findPosition(num, matrix, N, M) {
    for (let i = 0; i < N; i++) {
        for (let j = 0; j < M; j++) {
            if (matrix[i][j] === num) {
                return [i, j];
            }
        }
    }
    return [-1, -1]; // 不会发生
}

// 如果在Node.js环境中运行,调用main函数
main();

八、C算法源码

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

#define MAX_N 100

void selectNumbers(int matrix[MAX_N][MAX_N], int N, int M, int K, int* currentSelection, int currentSize, int* minKthValues, int* minKthValuesSize);
int canBeSelected(int row, int col, int* currentSelection, int currentSize, int matrix[MAX_N][MAX_N], int N, int M);
void findPosition(int num, int matrix[MAX_N][MAX_N], int N, int M, int* row, int* col);

int main() {
    int N, M, K;
    int matrix[MAX_N][MAX_N];

    scanf("%d %d %d", &N, &M, &K);

    // 读取矩阵
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            scanf("%d", &matrix[i][j]);
        }
    }

    // 存储每个组合的第K大的最小值
    int minKthValues[MAX_N * MAX_N];
    int minKthValuesSize = 0;
    int currentSelection[MAX_N];

    // 从矩阵中选择 K 个数字
    selectNumbers(matrix, N, M, K, currentSelection, 0, minKthValues, &minKthValuesSize);

    // 找到所有组合中的第 K 大的最小值
    int result = minKthValues[0];
    for (int i = 1; i < minKthValuesSize; i++) {
        if (minKthValues[i] < result) {
            result = minKthValues[i];
        }
    }

    printf("%d\n", result);

    return 0;
}

void selectNumbers(int matrix[MAX_N][MAX_N], int N, int M, int K, int* currentSelection, int currentSize, int* minKthValues, int* minKthValuesSize) {
    if (currentSize == K) {
        // 对于每个选择,找到第 K 大的值
        int sortedSelection[MAX_N];
        for (int i = 0; i < K; i++) {
            sortedSelection[i] = currentSelection[i];
        }
        // 排序选择的元素
        for (int i = 0; i < K - 1; i++) {
            for (int j = 0; j < K - i - 1; j++) {
                if (sortedSelection[j] > sortedSelection[j + 1]) {
                    int temp = sortedSelection[j];
                    sortedSelection[j] = sortedSelection[j + 1];
                    sortedSelection[j + 1] = temp;
                }
            }
        }
        minKthValues[(*minKthValuesSize)++] = sortedSelection[K - 1];
        return;
    }

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (canBeSelected(i, j, currentSelection, currentSize, matrix, N, M)) {
                currentSelection[currentSize] = matrix[i][j];
                selectNumbers(matrix, N, M, K, currentSelection, currentSize + 1, minKthValues, minKthValuesSize);
            }
        }
    }
}

int canBeSelected(int row, int col, int* currentSelection, int currentSize, int matrix[MAX_N][MAX_N], int N, int M) {
    // 检查行列约束
    for (int i = 0; i < currentSize; i++) {
        int r, c;
        findPosition(currentSelection[i], matrix, N, M, &r, &c);
        if (r == row || c == col) {
            return 0;
        }
    }
    return 1;
}

void findPosition(int num, int matrix[MAX_N][MAX_N], int N, int M, int* row, int* col) {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (matrix[i][j] == num) {
                *row = i;
                *col = j;
                return;
            }
        }
    }
    *row = -1;
    *col = -1;  // 不会发生
}

九、C++算法源码

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

#define MAX_N 100

void selectNumbers(int matrix[MAX_N][MAX_N], int N, int M, int K, vector<int>& currentSelection, vector<int>& minKthValues);
bool canBeSelected(int row, int col, const vector<int>& currentSelection, int matrix[MAX_N][MAX_N], int N, int M);
pair<int, int> findPosition(int num, int matrix[MAX_N][MAX_N], int N, int M);

int main() {
    int N, M, K;
    int matrix[MAX_N][MAX_N];

    cin >> N >> M >> K;

    // 读取矩阵
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cin >> matrix[i][j];
        }
    }

    // 存储每个组合的第K大的最小值
    vector<int> minKthValues;
    vector<int> currentSelection;

    // 从矩阵中选择 K 个数字
    selectNumbers(matrix, N, M, K, currentSelection, minKthValues);

    // 找到所有组合中的第 K 大的最小值
    int result = *min_element(minKthValues.begin(), minKthValues.end());

    cout << result << endl;

    return 0;
}

void selectNumbers(int matrix[MAX_N][MAX_N], int N, int M, int K, vector<int>& currentSelection, vector<int>& minKthValues) {
    if (currentSelection.size() == K) {
        // 对于每个选择,找到第 K 大的值
        vector<int> sortedSelection = currentSelection;
        sort(sortedSelection.begin(), sortedSelection.end());
        minKthValues.push_back(sortedSelection[K - 1]);
        return;
    }

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (canBeSelected(i, j, currentSelection, matrix, N, M)) {
                currentSelection.push_back(matrix[i][j]);
                selectNumbers(matrix, N, M, K, currentSelection, minKthValues);
                currentSelection.pop_back();
            }
        }
    }
}

bool canBeSelected(int row, int col, const vector<int>& currentSelection, int matrix[MAX_N][MAX_N], int N, int M) {
    // 检查行列约束
    for (int num : currentSelection) {
        pair<int, int> position = findPosition(num, matrix, N, M);
        if (position.first == row || position.second == col) {
            return false;
        }
    }
    return true;
}

pair<int, int> findPosition(int num, int matrix[MAX_N][MAX_N], int N, int M) {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (matrix[i][j] == num) {
                return make_pair(i, j);
            }
        }
    }
    return make_pair(-1, -1); // 不会发生
}


🏆下一篇:华为OD机试真题 - 简易内存池(Python/JS/C/C++ 2024 E卷 200分)

🏆本文收录于,华为OD机试真题(Python/JS/C/C++)

刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加入华为OD刷题交流群,每一题都有详细的答题思路、详细的代码注释、3个测试用例、为什么这道题采用XX算法、XX算法的适用场景,发现新题目,随时更新,全天CSDN在线答疑。

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

哪 吒

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

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

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

打赏作者

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

抵扣说明:

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

余额充值