📜  门| GATE CS 2018 |第 52 题(1)

📅  最后修改于: 2023-12-03 15:28:37.904000             🧑  作者: Mango

门| GATE CS 2018 |第 52 题

本题是计算机科学与工程领域的GATE CS 2018试题中第52题。该题的难度为中等。

题目描述

有一个大小为 N 的正方形矩阵,其中每个元素可以为 01。你需要将其中一些元素修改为 1,使得任意一个大小为 3*3 的子矩阵中,恰好有一个元素为 1。你的任务是计算最小需要修改的元素数量。

输入格式

第一行输入一个整数 T,表示测试数据组数。对于每组数据,第一行输入一个正整数 N,表示正方形矩阵的大小。接下来 N 行,每行输入 N 个整数,表示矩阵中相应位置元素的值。

输出格式

对于每组数据,输出一行一个整数,表示最小需要修改的元素数量。

示例

输入:

2
3
1 0 0
0 0 0
0 0 0
4
1 0 0 0
0 0 0 0
0 0 1 0
0 0 0 0

输出:

1
2
解题思路

该题是一道矩阵题目,需要我们求解最小的修改数。其实我们可以发现,在一个合法的矩阵中,中心一定有且仅有一个 1

因此,我们需要对所有可能的中心位置枚举,统计所需要修改的元素数,最终取所有中心位置修改元素数的最小值作为答案即可。

还需要注意的是,对于边缘和角落位置,需要特别考虑,因为这些位置只有部分能够构成 $3*3$ 的矩阵,因此它们的结果需要特别的处理。

详见代码注释。

代码实现
def min_modifications(matrix):
    n = len(matrix)
    m = n + 2  # 为了方便处理边界和角落的情况,增加了额外的一圈

    # 生成额外的一圈,并将原矩阵赋值到中间部分
    extra_matrix = [[0] * m for _ in range(m)]
    for i in range(1, m - 1):
        for j in range(1, m - 1):
            extra_matrix[i][j] = matrix[i - 1][j - 1]

    min_count = float('inf')  # 记录最小修改元素数

    # 枚举中心位置,计算需要修改的元素数
    for i in range(1, m - 1):
        for j in range(1, m - 1):
            count = 0  # 记录修改元素数
            for x in range(-1, 2):  # 遍历 $3*3$ 中的所有位置
                for y in range(-1, 2):
                    if extra_matrix[i + x][j + y] == 1:
                        if x == 0 and y == 0:  # 中心位置必须是 $0$
                            count = float('inf')
                            break                        
                    else:
                        if abs(x) <= 1 and abs(y) <= 1:  # 靠近中心的位置必须是 $1$
                            count += 1
                if count == float('inf'):
                    break
            min_count = min(min_count, count)

    return min_count


if __name__ == "__main__":
    test_cnt = int(input().strip())
    for t in range(test_cnt):
        n = int(input().strip())
        matrix = []
        for i in range(n):
            line = input().strip().split()
            matrix.append([int(c) for c in line])
        count = min_modifications(matrix)
        print(count)

输出的markdown格式:

# 门| GATE CS 2018 | 第 52 题

## 题目描述

有一个大小为 `N` 的正方形矩阵,其中每个元素可以为 `0` 或 `1`。你需要将其中一些元素修改为 `1`,使得任意一个大小为 `3*3` 的子矩阵中,恰好有一个元素为 `1`。你的任务是计算最小需要修改的元素数量。

## 输入格式

第一行输入一个整数 `T`,表示测试数据组数。对于每组数据,第一行输入一个正整数 `N`,表示正方形矩阵的大小。接下来 `N` 行,每行输入 `N` 个整数,表示矩阵中相应位置元素的值。 

## 输出格式

对于每组数据,输出一行一个整数,表示最小需要修改的元素数量。

## 示例

输入:

2 3 1 0 0 0 0 0 0 0 0 4 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0


输出:

1 2


## 解题思路

该题是一道矩阵题目,需要我们求解最小的修改数。其实我们可以发现,在一个合法的矩阵中,中心一定有且仅有一个 `1`。

因此,我们需要对所有可能的中心位置枚举,统计所需要修改的元素数,最终取所有中心位置修改元素数的最小值作为答案即可。

还需要注意的是,对于边缘和角落位置,需要特别考虑,因为这些位置只有部分能够构成 $3*3$ 的矩阵,因此它们的结果需要特别的处理。

详见代码注释。

## 代码实现

```python
def min_modifications(matrix):
    n = len(matrix)
    m = n + 2  # 为了方便处理边界和角落的情况,增加了额外的一圈

    # 生成额外的一圈,并将原矩阵赋值到中间部分
    extra_matrix = [[0] * m for _ in range(m)]
    for i in range(1, m - 1):
        for j in range(1, m - 1):
            extra_matrix[i][j] = matrix[i - 1][j - 1]

    min_count = float('inf')  # 记录最小修改元素数

    # 枚举中心位置,计算需要修改的元素数
    for i in range(1, m - 1):
        for j in range(1, m - 1):
            count = 0  # 记录修改元素数
            for x in range(-1, 2):  # 遍历 $3*3$ 中的所有位置
                for y in range(-1, 2):
                    if extra_matrix[i + x][j + y] == 1:
                        if x == 0 and y == 0:  # 中心位置必须是 $0$
                            count = float('inf')
                            break                        
                    else:
                        if abs(x) <= 1 and abs(y) <= 1:  # 靠近中心的位置必须是 $1$
                            count += 1
                if count == float('inf'):
                    break
            min_count = min(min_count, count)

    return min_count


if __name__ == "__main__":
    test_cnt = int(input().strip())
    for t in range(test_cnt):
        n = int(input().strip())
        matrix = []
        for i in range(n):
            line = input().strip().split()
            matrix.append([int(c) for c in line])
        count = min_modifications(matrix)
        print(count)
时间复杂度

算法的时间复杂度为 $O(T*N^2)$,其中 $T$ 表示测试数据组数, $N$ 表示矩阵的大小。