擂台法中的初值设定
在之前的文章中,我介绍了“打擂台”算法。“打擂台”算法一般用于求最大值或者最小值问题。如果您还不了解它的规则,请先看我的这篇文章。
在“打擂台”算法中,擂主的初值一般是设成待处理数据的第一个数,这也是我推荐大家在解答编程题时使用的方法。但在GESP考试以及其他竞赛中,除了编程题,还有单选题和判断题,在这些题目中,出题者就不一定采用“第一个数作为擂主”的方法,而是采用另外一种方法——极值法,即先把擂主设成某个极值。
我们先来看一道判断题真题:下列代码能正确输出数组中的最小值2。
int main() {
int array[5] = {3, 7, 5, 2, 4};
int min = 0;
for (int i=0; i<5; i++)
{
if (array[i] < min)
min = array[i];
}
cout << min << endl;
return 0;
}
分析:这段代码使用了擂台法求最小值,但擂主的初值设成了0。虽然循环中“打擂”的逻辑是对的,但由于所有要判断的数都大于0,所以所有打擂都失败了,最后的结果为初值0,不是数组中的最小值。所以这道题的答案是错误。
这就是使用极值法时一个极其需要注意的地方:要求最小值时,要先把擂主设成一个尽量大的值。反过来,要求最大值时,要先把擂主设成一个尽量小的值。
具体到本题中,数组元素的类型为int,所以要把min的初值设成int型数的最大值,即2147483647。而如果要求最大值,则要把擂主的初值设成int型数的最小值-2147483648(注意不是-2147483647)。
由此可见,使用极值法时,对于最大值和最小值,初值要设成不同的极值,这已经容易产生混淆了,而记住极值是一件更加困难的事,很多初学者根本记不住int型数的两个极值。所以,笔者强烈建议:解答编程题时,尽量使用第一个值作为擂主的初值。
具体到本题,可以这样修改代码:
//擂台法求数组的最小值
int main() {
int array[5] = {3, 7, 5, 2, 4};
int min = array[0]; //擂主先设为第一个数
for (int i=1; i<5; i++) //循环从第二个数开始
{
if (array[i] < min)
min = array[i];
}
cout << min << endl;
return 0;
}
如果要求最大值,只需修改一个符号(变量名的修改非必须):
//擂台法求数组的最大值
int main() {
int array[5] = {3, 7, 5, 2, 4};
int max = array[0]; //擂主先设为第一个数
for (int i=1; i<5; i++) //循环从第二个数开始
{
if (array[i] > max) //此处把<改成>
max = array[i];
}
cout << max << endl;
return 0;
}
这里需要注意的是,使用第一个数作为擂主时,循环必须从第二个数开始。虽然在本题中,循环从第一个数开始也不会有错(第一个数挑战自己一定失败),但在有些情况下,循环从第一个数开始就不对了。
例如,待处理的数据需要从屏幕或者文件读入(这也是通常的情况),此时先读入第一个数并设为擂主。如果接下来循环仍然从第一个数开始,那么第一个数要被读入两次,结果是数据不够。以下代码是错误的:
//错误的写法
int main() {
int n, a, min;
cin >> n >> a; //读入n和第一个数
min = a; //擂主先设为第一个数
for (int i=0; i<n; i++) //循环从第一个数开始,第一个数读了两次,导致数据不够
{
cin >> a;
if (a < min)
min = a;
}
cout << min << endl;
return 0;
}
此时,循环一定要从第二个数开始。
本文为学漄乐码堂主撰写。堂主已出版《GESP直通车——C++精简讲练》系列,一级到五级。

如果您想要学到真正的知识,而不只是应试的技巧,欢迎留言跟我联系。
(写作不易,请大家点赞、关注、收藏、转发!)
更多推荐


所有评论(0)