先看一下题目
鞍点:把每一个数值理解为坐标值,那么鞍点就是其坐标值在此行最大,同时在此列最小的坐标。
题目要求输出该坐标。
四个测试点:
方法一:不利用自定义函数
思路:根据题目,我们要找出此行的最大值,那就要依次遍历数组的每一行,找出该行的最大值。这一步其实是非常简单的,不过多介绍,利用for循环即可。
for (i = 0;i < n;i++) {//遍历每一行,一共n行。
int max = a[i][0];
int col_of_max = 0;//令此行的第一列为最大值。
for (j = 1;j < n;j++) {//依次遍历每一列,从第二列开始。
if (a[i][j] > max) {//若某列的值大于原先设定的最大值,则替换。
max = a[i][j];
col_of_max = j;
}
}
}
找到某行的最大值后,要判断该值是否为所在列的最小值,如果此列存在任何一个数小于该值,就可以判定此点不是鞍点;若不存在,则为鞍点,程序结束(因为题目说的是只有一个鞍点)。
接下来就是判断该最大值max是否为所在列的最小值min的代码。
//max(所在行最大)已知
int min = max;
for(int row = 0;row < n;row++){//从第0行的col_of_max列开始,依次遍历到第n-1行的col_of_max列。
int found = 1;
if(a[row][col_of_max] < min){
found = 0;//若存在比min还小的值,则说明不是鞍点,利用break结束循环。
break;
}
}
如果found为真,则满足题目要求,输出坐标,return 0以结束程序。
如果写道这就提交了答案,你会发现
易错:无法通过测试点2
测试点2:最大规模,有并列极值元素,最后一个是鞍点。
什么意思呢?就是在判断某行最大值的时候,我们所写的代码其实得到的col_of_max是最小的,后面可能还存在多个最大值(都相等),判断第一个后如果不是鞍点,循环直接结束了,导致并没有机会判断后面的最大值是否为其所在列的最小值。
那么如何改进?
就是解决上面存在的问题,在得到第一个最大值点不是鞍点后,使有机会判断后面的最大值是否为其所在列的最小值。
这就简单了,判断的方法跟上面的代码一模一样,就是再嵌套一个循环。
for (j = col_of_max + 1;j < n;j++) {
if (a[i][j] == max) {//如果使最大值,则再判断。
col_of_max = j;
for (int row = 0;row < n;row++) {//以下代码跟上面一样的,仔细思考一下。
found = 1;
if (a[row][col_of_max] < min) {
found = 0;
break;
}
}
if (found) {
printf("%d %d", i, col_of_max);
return 0;
}
}
}
现在把每一段代码组合起来
完整代码:
#include <stdio.h>
int main(void)
{
int a[6][6];
int n;
scanf_s("%d", &n);
int i, j;
for (i = 0;i < n;i++) {
for (j = 0;j < n;j++) {
scanf_s("%d", &a[i][j]);//对数组赋值。
}
}
int found = 1;
for (i = 0;i < n;i++) {
int max = a[i][0];
int col_of_max = 0;
for (j = 1;j < n;j++) {//找到此行的最大值,其下标为多个最大值中的最小下标
if (a[i][j] > max) {
max = a[i][j];
col_of_max = j;
}
}
int min = max;//如果为鞍点,则此行最大值为该列最小值。
for (int row = 0;row < n;row++) {
found = 1;//对found赋初值为一,假设找到了鞍点。
if (a[row][col_of_max] < min) {
found = 0;//若找到了更小的值,则不是鞍点,对found赋值为0,表示未找到。
break;
}
}
if (found) {//如果找到了,即found为一,输出坐标。
printf("%d %d", i, col_of_max);
return 0;//结束程序,因为题目说只有一个。
}
//如果程序来到了这一步,说明没有找到。
for (j = col_of_max + 1;j < n;j++) {
if (a[i][j] == max) {//寻找此行的相等极值。
col_of_max = j;
for (int row = 0;row < n;row++) {//与上同。
found = 1;
if (a[row][col_of_max] < min) {
found = 0;
break;
}
}
if (found) {
printf("%d %d", i, col_of_max);
return 0;
}
}
}
}
printf("NO");//如果找到了鞍点,则直接结束,不会执行此输出。若没有找到,程序会正常的走到这一步,输出NO,表示没有鞍点,随后程序结束。
return 0;
}
方法二:利用自定义函数。
这个方法的思路也很简单,就是一个“与”门,如果此行的最大值,此列的最小值都为真,就通过此门,输出坐标。
先写主函数:
int main(void)
{
int n;
scanf_s("%d", &n);
int i, j;
for (i = 0;i < n;i++) {
for (j = 0;j < n;j++) {
scanf_s("%d", &a[i][j]);
}
}
int found = 0;//没找到。
for (i = 0;i < n;i++) {//认真理解一下我定义的函数名。
for (j = 0;j < n;j++) {
if (max_of_row(n, i, j)) {//第一个门。
if (min_of_col(n, i, j)) {//第二个门。
printf("%d %d", i, j);
found = 1;//找到了。
return 0;
}
}
}
}
if (!found) {
printf("NONE");
}
return 0;
}
就这短短的几行,毫无技术含量。
再写一下自定义函数吧。
第一个自定义函数:判断最大值
int max_of_row(int n, int row, int col) {
int max = a[row][col];//这是一个确定的数,下面是为了判断该值是否是此row最大的。
int ismax = 1;//假设ismax为真。
for (col = 0;col < n;col++) {//因此遍历每一列‘
if (a[row][col] > max) {
ismax = 0;//存在更大的,则ismax为假。
break;
}
}
return ismax;//返回真假。
}
第二个自定义函数:判断最小值
这个自定义函数实现方法与第一个一模一样,我就不做注释了。
int min_of_col(int n, int row, int col) {
int min = a[row][col];
int ismin = 1;
for (row = 0;row < n;row++) {
if (a[row][col] < min) {
ismin = 0;
break;
}
}
return ismin;
}
需要注意的是,无论是在主函数中,还是在两个自定义函数中,都是利用的同一个二维数组,因此我把它定义为了全局变量。
完整代码:
#include <stdio.h>
int max_of_row(int n, int row, int col);
int min_of_col(int n, int row, int col);
int a[6][6];
int main(void)
{
int n;
scanf_s("%d", &n);
int i, j;
for (i = 0;i < n;i++) {
for (j = 0;j < n;j++) {
scanf_s("%d", &a[i][j]);
}
}
int found = 0;
for (i = 0;i < n;i++) {
for (j = 0;j < n;j++) {
if (max_of_row(n, i, j)) {
if (min_of_col(n, i, j)) {
printf("%d %d", i, j);
found = 1;
return 0;
}
}
}
}
if (!found) {
printf("NONE");
}
return 0;
}
int max_of_row(int n, int row, int col) {
int max = a[row][col];
int ismax = 1;
for (col = 0;col < n;col++) {
if (a[row][col] > max) {
ismax = 0;
break;
}
}
return ismax;
}
int min_of_col(int n, int row, int col) {
int min = a[row][col];
int ismin = 1;
for (row = 0;row < n;row++) {
if (a[row][col] < min) {
ismin = 0;
break;
}
}
return ismin;
}
思考:
这两种方法都严格按照题目的要求无法对存在的多个鞍点一并输出,但其实只要对两个代码分别进行小小修改,就可以输出所有的鞍点,自己修改一下吧!