求一个矩阵中的鞍点
题目描述
# T248896 05-17-C02-求一个矩阵中的鞍点(L4)
## 题目描述
编程求一个4×4矩阵(就是二维数组)中的鞍点,如果没有鞍点,则输出提示信息。
鞍点是二维数组中的一个元素,它在它所在那一行上最大,在它所在那一列上最小。
## 输入格式
输入数据占4行,每行有4个整数,范围不超过int型的范围。
## 输出格式
如果不存在鞍点,则输出“no saddle”;如果存在鞍点,则输出所有鞍点,每个鞍点占一行,为3个整数,分别表示鞍点的值,以及它的行号和列号(行号和列号均从1开始计起),多个鞍点先按行优先、再按列优先的顺序输出。
## 输入输出样例 #1
### 输入 #1
```
5 12 23 56 19 28 37 46 -12 -34 6 8 97 25 -7 45
```
### 输出 #1
```
8 3 4
```
## 输入输出样例 #2
### 输入 #2
```
5 12 23 56 19 28 37 46 -12 -34 6 58 97 25 -7 45
```
### 输出 #2
```
no saddle
```
## 输入输出样例 #3
### 输入 #3
```
70 -77 -93 -25 55 -64 -36 -10 63 -91 -22 -12 55 20 -59 -81
```
### 输出 #3
```
55 2 1
55 4 1
```
## 输入输出样例 #4
### 输入 #4
```
28 -5 50 71 4 -44 12 18 70 30 -47 36 -54 -70 -54 -54
```
### 输出 #4
```
-54 4 1
-54 4 3
-54 4 4
```
## 说明/提示
### 本题出处
本题源自以下教材的编程习题:王桂平, 周祖松, 穆云波, 葛昌威编著. C++趣味编程及算法入门. 北京大学出版社, 2024年出版.
一、题目分析
题目要求在一个 4×4 的矩阵中寻找 “鞍点”。鞍点的定义是:矩阵中的一个元素,它既是所在行的最大值,又是所在列的最小值。若存在多个鞍点,需按行优先、列优先的顺序输出(即先按行号从小到大,同一行内按列号从小到大);若不存在鞍点,输出 “no saddle”。
二、核心思路
要找到鞍点,需分两步判断每个元素:
- 该元素是否是其所在行的最大值;
- 该元素是否是其所在列的最小值。
为提高效率,可先预处理矩阵,计算出每一行的最大值和每一列的最小值,存储在临时变量中,再逐个元素验证是否同时满足上述两个条件。
三、代码实现步骤详解
1. 引入头文件与命名空间
cpp
运行
#include<bits/stdc++.h> // 包含所有标准库,简化代码
using namespace std;
2. 定义矩阵并读取输入
cpp
运行
int a[5][5]; // 定义5×5数组(下标1~4用于存储4×4矩阵,0行0列用于存储中间结果)
int i,j;// 读取4×4矩阵,行号i和列号j从1开始(方便后续输出行号列号)
for(i = 1; i < 5; i++){ // i=1~4(4行)for(j = 1; j < 5; j++){ // j=1~4(4列)cin >> a[i][j]; // 存储元素到a[i][j]}
}
说明:使用 5×5 数组而非 4×4,是为了用a[0][j]
存储第 j 列的最小值,a[i][0]
存储第 i 行的最大值,避免占用有效数据的下标。
3. 计算每列的最小值(存储在第 0 行)
cpp
运行
for(j = 1; j < 5; j++){ // 遍历每一列(j=1~4)int mn = a[1][j]; // 初始假设第j列第1行的元素是最小值for(i = 2; i < 5; i++){ // 比较第j列的其他元素(行i=2~4)if(a[i][j] < mn){ // 若找到更小的元素mn = a[i][j]; // 更新最小值}}a[0][j] = mn; // 第j列的最小值存入a[0][j]
}
4. 计算每行的最大值(存储在第 0 列)
cpp
运行
for(i = 1; i < 5; i++){ // 遍历每一行(i=1~4)int mx = a[i][1]; // 初始假设第i行第1列的元素是最大值for(j = 2; j < 5; j++){ // 比较第i行的其他元素(列j=2~4)if(a[i][j] > mx){ // 若找到更大的元素mx = a[i][j]; // 更新最大值}}a[i][0] = mx; // 第i行的最大值存入a[i][0]
}
5. 查找并输出鞍点
cpp
运行
bool flag = false; // 标记是否找到鞍点,初始为false// 按行优先、列优先遍历所有元素(i=1~4行,j=1~4列)
for(i = 1; i < 5; i++){for(j = 1; j < 5; j++){// 若当前元素既是所在行的最大值(等于a[i][0]),又是所在列的最小值(等于a[0][j])if(a[i][j] == a[i][0] && a[i][j] == a[0][j]){// 输出:元素值、行号、列号(行号列号从1开始,与i、j直接对应)cout << a[i][j] << " " << i << " " << j << endl;flag = true; // 标记已找到鞍点}}
}// 若未找到鞍点,输出提示信息
if(flag == false){cout << "no saddle" << endl;
}
四、关键逻辑解析
-
数组下标设计:用
a[1][1]~a[4][4]
存储 4×4 矩阵的有效元素,a[0][j]
(j=1~4)存储第 j 列的最小值,a[i][0]
(i=1~4)存储第 i 行的最大值。这种设计避免了额外定义数组,且方便直接通过 i、j 获取行号和列号(无需转换)。 -
行最大值与列最小值的预处理:先一次性计算所有行的最大值和列的最小值,存储在第 0 行和第 0 列,后续判断时直接读取,避免重复计算,提高效率。
-
鞍点判断条件:元素
a[i][j]
必须同时满足:- 等于所在行的最大值(
a[i][j] == a[i][0]
) - 等于所在列的最小值(
a[i][j] == a[0][j]
)
- 等于所在行的最大值(
-
输出顺序:遍历顺序为
i从1到4
(行优先),同一行内j从1到4
(列优先),自然满足题目要求的输出顺序。
五、示例测试解析
样例 1 输入:
plaintext
5 12 23 56
19 28 37 46
-12 -34 6 8
97 25 -7 45
-
计算列最小值(a[0][j]):第 1 列:min (5,19,-12,97) = -12第 2 列:min (12,28,-34,25) = -34第 3 列:min (23,37,6,-7) = -7第 4 列:min (56,46,8,45) = 8
-
计算行最大值(a[i][0]):第 1 行:max (5,12,23,56) = 56第 2 行:max (19,28,37,46) = 46第 3 行:max (-12,-34,6,8) = 8第 4 行:max (97,25,-7,45) = 97
-
判断鞍点:第 3 行第 4 列的元素
8
,等于行最大值(8)和列最小值(8),因此是鞍点。输出:8 3 4
。
样例 3 输入:
plaintext
70 -77 -93 -25
55 -64 -36 -10
63 -91 -22 -12
55 20 -59 -81
-
列最小值(第 1 列):min (70,55,63,55) = 55
-
行最大值:第 2 行:max (55,-64,-36,-10) = 55第 4 行:max (55,20,-59,-81) = 55
-
鞍点:第 2 行第 1 列(55)和第 4 行第 1 列(55)均满足条件,按行优先输出,结果为:
55 2 1
55 4 1
样例 4 输入:
plaintext
28 -5 50 71
4 -44 12 18
70 30 -47 36
-54 -70 -54 -54
-
行最大值(第 4 行):max(-54,-70,-54,-54) = -54
-
列最小值:第 1 列:min (28,4,70,-54) = -54第 3 列:min (50,12,-47,-54) = -54第 4 列:min (71,18,36,-54) = -54
-
鞍点:第 4 行中列 1、3、4 的元素均为 - 54,且满足条件,输出:
-54 4 1
-54 4 3
-54 4 4
六、完整代码
cpp
运行
#include<bits/stdc++.h>
using namespace std;
int main(){int a[5][5],i,j;// 读取4×4矩阵(行号、列号从1开始)for(i = 1; i < 5; i++){for(j = 1; j < 5; j++)cin >> a[i][j];}// 计算每列的最小值,存储在第0行for(j = 1; j < 5; j++){int mn = a[1][j];for(i = 2; i < 5; i++){if(a[i][j] < mn) mn = a[i][j];}a[0][j] = mn;}// 计算每行的最大值,存储在第0列for(i = 1; i < 5; i++){int mx = a[i][1];for(j = 2; j < 5; j++){if(a[i][j] > mx) mx = a[i][j];}a[i][0] = mx;}// 查找并输出鞍点bool flag = false;for(i = 1; i < 5; i++){for(j = 1; j < 5; j++){if(a[i][j] == a[i][0] && a[i][j] == a[0][j]){cout << a[i][j] << " " << i << " " << j << endl;flag = true;}}}// 未找到鞍点时输出提示if(flag == false) cout << "no saddle" << endl;return 0;
}