新鲜出炉——2020 USACO 公开赛题目解析!

2020 年的USACO 公开赛已经落下帷幕,这场公开赛的举办时间为美国时间3月27日到30日,在这个时间窗口期,任何时候都可以登陆网站开始考试,考试一旦开启,必须在5 个小时内提交答案,在此期间,你可以查询任何资料,只要最终提交的答案能够通过测试就算通过,也就是说,它是一个开放式的考试,要求的是解决问题的能力,任何能够查到的需要死记硬背的东西,原则上你都不需要记忆,你需要锻炼的是如何利用这些知识,真正解决最终的问题。

今年的题目是以新冠病毒为引子出题的,这里我们先找一道铜牌组的题目解析一下:

usaco题目-1.png

英文不好的学生也不用担心,USACO的考试非常贴心,正式考试的时候可以选择中文版本的。

在正式解析题目前,我想先向大家介绍一种解题方法,这种方法出自于大数学家G-波利亚(G-Polya),他在成名以前是一名中学数学老师,计算机的鼻祖冯诺伊曼就曾经是他的学生,而当今的数学界天才人物陶哲轩,小时候也曾用这种方法来准备奥数比赛。这是一种简单,靠谱,稳定的解决问题的方法,叫做四步解题法。

  1. 理解题目
    对你所不理解的问题作出答复是愚蠢的,在正式解答题目前,应该首先对题目有一个深入的了解,知道题目中哪些是未知量,哪些是已知量,给的条件有哪些?最好能够用自己的话把题目概括一下,这样能够加深对题目的了解。理解题目的这个步骤促使你真正的知道目标是什么,现状是什么,条件有哪些,只有理解了这三方面的背景,才能设计出路径达到目标。

  2. 拟定方案
    所谓的拟定方案,就是知道为了求解未知量我们必须做哪些计算或者做哪些图,也就是一个从已知量到求解未知量的方案。解答一个题目的主要成就就在于构思一个解题方案的思路,而获得思路取决于你过往解决问题的经验和已经掌握的知识点,这些是思路的来源。

  3. 执行方案
    获得思路需要知识,良好的习惯,专注力,还要有运气,相比而言,执行方案相对简单,主要靠耐心。对于编程来说,执行方案就意味着把思路用程序表达出来,原则上,只要思路理清楚了,编程语言又还比较熟悉的话,肯定是没有问题的,但在编写的过程中,一定会有错误,需要不断进行调试。

  4. 总结
    绝对不能解决完问题就了事,那就浪费了巩固和提升技巧的机会。做完题后,可以再检查一遍解题方案,可以反思下是否还有更加优化的方案,或者这种解题方法是否适用于其他场景。主动制造反馈,抓住举一反三的机会,总结是最好的启发时刻。

好了,万能的四步解题法已经介绍完毕了,但相信不少同学应该仅仅只停留在了字面理解的层次上,那么接下来我们就用铜牌组的这道例题,来演绎下四步法到底应该如何运用。

拿到题目后,首先要认真读一遍题目,从字面意思了解题目,最好能够达到可以使用自己的话复述题目的程度,这样题目中的已知,未知以及给出的条件等都印在了你的脑中。最重要的是,要搞清楚这道题目求的是什么,这个就是目标。 简单概括的话,这道例题中给出了当前牛棚中所有牛的生病状态,也就是说,我们明确知道某一头牛到底是感染了还是没有感染。题目给出的条件是,牛之间的感染是有一个感染半径的,低于这个半径的牛之间会相互传染,而大于这个半径的牛不会相互感染。最终题目要求的未知量是,在初始状态下,最少有几头牛是被感染的。 如果你能够按照上述这样,明确的概括出已知,条件和未知,那么基本上这道题目算了理解了。

接下来就要拟定方案了,这一步是最难的,而且根据每个学生的知识结构和思维方式不同,也会制定出不同的方案。这一步最重要的是要考虑下曾经是否做过类似的题目,或者说能够把这个问题归到某一类算法中。在这道题目中,想要求出未知量,很显然首先要知道感染半径是多少,确定了感染半径后,牛之间的距离小于半径的可以归并在一个集合中,每个集合中只要一头牛感染了,就会把这个集合中其他的牛都感染。所以根据感染半径和牛的位置信息,求出能够归并的集合数量,这个数量就等于最初状况下有几头牛是感染的。

思路一旦有了之后,执行方案的阶段就是通过编程把方案落地,一般如果掌握了基本的编程语言后,这一步都没啥太大问题,当然,语言在编写的过程中会出现错误,可以根据题目给出的样例数据进行验证,直到确保程序是按照既定方案在执行。

在信息学的竞赛中,对程序的执行时间会有要求,所以即使你的思路和代码都是正确的,但最终执行时超过既定时间,这也无法通过考核。在这种情况下,就要重新反思下拟定的方案是否还有更优解。例如有些使用穷举算法的解题思路,很可能会因为尝试的例子太多导致时间超时,这时候就要考虑如何能够去掉一些不必要的尝试,从而缩短时间。

接下来,就给出这道题目的代码供大家学习参考,以下是C++ 版本的实现代码:

#include 
#include 
#include 
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++ 是由两个不同的人给出的实现方案,你从代码上能够看出哪个版本效率更高吗,这个留作一个思考题,大家看完代码后思考下哦。

你可能感兴趣的:(新鲜出炉——2020 USACO 公开赛题目解析!)