找鞍点:两种方法的讲解。

先看一下题目

鞍点:把每一个数值理解为坐标值,那么鞍点就是其坐标值在此行最大,同时在此列最小的坐标。

题目要求输出该坐标。

四个测试点:

方法一:不利用自定义函数

思路:根据题目,我们要找出此行的最大值,那就要依次遍历数组的每一行,找出该行的最大值。这一步其实是非常简单的,不过多介绍,利用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;
}

思考:

这两种方法都严格按照题目的要求无法对存在的多个鞍点一并输出,但其实只要对两个代码分别进行小小修改,就可以输出所有的鞍点,自己修改一下吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值