LuoguB2102 计算鞍点 题解

Content

给定一个 \(5\times 5\) 的矩阵,请在这个矩阵中找出一个元素,使得这个元素既是它所在行的最大值,也是它所在列的最小值。

Solution

如果直接暴力枚举每一个元素,再去算每一个元素所在行的最大值和所在列的最小值,再比较,虽然也可以通过这道题目,但是太麻烦了。有没有更简单的方法?

答案是肯定的。

我们发现对于同一行的元素,每次计算所在行的最大值其实是重复 \(5\) 次了的,同样地,我们发现对于同一列的元素,每次计算所在列的最小值其实也是重复 \(5\) 次了的。有没有不重复的方法?预处理。我们在整个程序的核心部分开始之前,先预处理每一行和每一列,求出每一行的最大值和每一列的最小值。这样的复杂度如果是 \(n\times n\) 的矩阵的话是 \(\mathcal O(n^2)\) 的(即先枚举每一行或每一列,再枚举每一行或每一列的元素取最值)。然后我们就可以在执行程序的时候,直接拿预处理出来的最大值和最小值比较输出就好了。

预处理的优势在本题中尽管没有很大的体现,但是在今后的信息学习中,你将可以看到预处理发挥的巨大的优化复杂度的作用。

Code

#include <cstdio>
#include <algorithm> //因为要用到 max 和 min 函数
using namespace std;

int fl = 0; //用来判断是否有鞍点
long long a[7][7], col[7], row[7];

int main() {
    for(int i = 1; i <= 5; ++i) row[i] = -0x3f3f3f3f3f3f3f3f, col[i] = 0x3f3f3f3f3f3f3f3f; //C++ 中,0x开头的后面数是十六进制。
    for(int i = 1; i <= 5; ++i) for(int j = 1; j <= 5; ++j) a[i][j] = Rll;
    for(int i = 1; i <= 5; ++i) for(int j = 1; j <= 5; ++j) row[i] = max(row[i], a[i][j]);
    for(int j = 1; j <= 5; ++j) for(int i = 1; i <= 5; ++i)  col[j] = min(col[j], a[i][j]); //想想这里为什么要先循环 j 再循环 i。
    for(int i = 1; i <= 5; ++i) for(int j = 1; j <= 5; ++j) if(a[i][j] == col[j] && a[i][j] == row[i]) {printf("%d %d %lld", i, j, a[i][j]), fl = 1; break;}
    if(!fl) printf("not found");
    return 0;
}
posted @ 2021-12-15 21:49  Eason_AC  阅读(411)  评论(0)    收藏  举报