2020 年的USACO 公开赛已经落下帷幕,这场公开赛的举办时间为美国时间3月27日到30日,在这个时间窗口期,任何时候都可以登陆网站开始考试,考试一旦开启,必须在5 个小时内提交答案,在此期间,你可以查询任何资料,只要最终提交的答案能够通过测试就算通过,也就是说,它是一个开放式的考试,要求的是解决问题的能力,任何能够查到的需要死记硬背的东西,原则上你都不需要记忆,你需要锻炼的是如何利用这些知识,真正解决最终的问题。
今年的题目是以新冠病毒为引子出题的,这里我们先找一道铜牌组的题目解析一下:
usaco题目-1.png英文不好的学生也不用担心,USACO的考试非常贴心,正式考试的时候可以选择中文版本的。
在正式解析题目前,我想先向大家介绍一种解题方法,这种方法出自于大数学家G-波利亚(G-Polya),他在成名以前是一名中学数学老师,计算机的鼻祖冯诺伊曼就曾经是他的学生,而当今的数学界天才人物陶哲轩,小时候也曾用这种方法来准备奥数比赛。这是一种简单,靠谱,稳定的解决问题的方法,叫做四步解题法。
-
理解题目
对你所不理解的问题作出答复是愚蠢的,在正式解答题目前,应该首先对题目有一个深入的了解,知道题目中哪些是未知量,哪些是已知量,给的条件有哪些?最好能够用自己的话把题目概括一下,这样能够加深对题目的了解。理解题目的这个步骤促使你真正的知道目标是什么,现状是什么,条件有哪些,只有理解了这三方面的背景,才能设计出路径达到目标。 -
拟定方案
所谓的拟定方案,就是知道为了求解未知量我们必须做哪些计算或者做哪些图,也就是一个从已知量到求解未知量的方案。解答一个题目的主要成就就在于构思一个解题方案的思路,而获得思路取决于你过往解决问题的经验和已经掌握的知识点,这些是思路的来源。 -
执行方案
获得思路需要知识,良好的习惯,专注力,还要有运气,相比而言,执行方案相对简单,主要靠耐心。对于编程来说,执行方案就意味着把思路用程序表达出来,原则上,只要思路理清楚了,编程语言又还比较熟悉的话,肯定是没有问题的,但在编写的过程中,一定会有错误,需要不断进行调试。 -
总结
绝对不能解决完问题就了事,那就浪费了巩固和提升技巧的机会。做完题后,可以再检查一遍解题方案,可以反思下是否还有更加优化的方案,或者这种解题方法是否适用于其他场景。主动制造反馈,抓住举一反三的机会,总结是最好的启发时刻。
好了,万能的四步解题法已经介绍完毕了,但相信不少同学应该仅仅只停留在了字面理解的层次上,那么接下来我们就用铜牌组的这道例题,来演绎下四步法到底应该如何运用。
拿到题目后,首先要认真读一遍题目,从字面意思了解题目,最好能够达到可以使用自己的话复述题目的程度,这样题目中的已知,未知以及给出的条件等都印在了你的脑中。最重要的是,要搞清楚这道题目求的是什么,这个就是目标。 简单概括的话,这道例题中给出了当前牛棚中所有牛的生病状态,也就是说,我们明确知道某一头牛到底是感染了还是没有感染。题目给出的条件是,牛之间的感染是有一个感染半径的,低于这个半径的牛之间会相互传染,而大于这个半径的牛不会相互感染。最终题目要求的未知量是,在初始状态下,最少有几头牛是被感染的。 如果你能够按照上述这样,明确的概括出已知,条件和未知,那么基本上这道题目算了理解了。
接下来就要拟定方案了,这一步是最难的,而且根据每个学生的知识结构和思维方式不同,也会制定出不同的方案。这一步最重要的是要考虑下曾经是否做过类似的题目,或者说能够把这个问题归到某一类算法中。在这道题目中,想要求出未知量,很显然首先要知道感染半径是多少,确定了感染半径后,牛之间的距离小于半径的可以归并在一个集合中,每个集合中只要一头牛感染了,就会把这个集合中其他的牛都感染。所以根据感染半径和牛的位置信息,求出能够归并的集合数量,这个数量就等于最初状况下有几头牛是感染的。
思路一旦有了之后,执行方案的阶段就是通过编程把方案落地,一般如果掌握了基本的编程语言后,这一步都没啥太大问题,当然,语言在编写的过程中会出现错误,可以根据题目给出的样例数据进行验证,直到确保程序是按照既定方案在执行。
在信息学的竞赛中,对程序的执行时间会有要求,所以即使你的思路和代码都是正确的,但最终执行时超过既定时间,这也无法通过考核。在这种情况下,就要重新反思下拟定的方案是否还有更优解。例如有些使用穷举算法的解题思路,很可能会因为尝试的例子太多导致时间超时,这时候就要考虑如何能够去掉一些不必要的尝试,从而缩短时间。
接下来,就给出这道题目的代码供大家学习参考,以下是C++ 版本的实现代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define MAX_N 1010
#define INF 100000000
int N;
struct COW{
int x;
int s;
}cow[MAX_N];
bool cmp(struct COW a, struct COW b)
{
return a.x < b.x;
}
void setIO(string s) {
ios_base::sync_with_stdio(0); cin.tie(0);
freopen((s+".in").c_str(),"r",stdin);
freopen((s+".out").c_str(),"w",stdout);
}
int main() {
setIO("socdist2");
cin >> N;
for(int i = 0; i < N; i++)
{
cin >> cow[i].x >> cow[i].s;
}
sort(cow, cow+N, cmp);
int minl = INF;
for(int i = 1; i < N; i++)
{
if(cow[i].s == 0 && cow[i-1].s == 1)
minl = min(minl, cow[i].x - cow[i-1].x);
if(cow[i].s == 1 && cow[i-1].s == 0)
minl = min(minl, cow[i].x - cow[i-1].x);
}
int count = cow[0].s != 0;
for(int i = 1; i < N; i++)
{
if(cow[i].s == 1)
{
if(cow[i].x - cow[i-1].x >= minl)
count ++;
}
}
cout << count << endl;
}
Python 的版本就不贴出来了,给一个下载链接吧:
链接:https://pan.baidu.com/s/1vizpVujpMbuoXluQ2iGxGA
密码:338u
其中Python 和 C++ 是由两个不同的人给出的实现方案,你从代码上能够看出哪个版本效率更高吗,这个留作一个思考题,大家看完代码后思考下哦。
网友评论