noip2003提高组题解
这一年的前三题虽然难度不高,但是第二题极为繁琐,想在考场上用较短的时间拿到第二题的分数难上加难。所以必须要调整策略,争取拿其他三题的分数。第四题是比较普通的搜索题,分数比较好拿,但是很容易想成树形DP,就只能拿30~50分。
第一题:神经网络
模拟
有几个注意点:
- 输入层(即第一层)的结点的U(阈值)是没有用的;
- 题目说输出「最后状态非零的输出层神经元状态」,但实际上输出的是状态大于0的值。
由于没有注意到神经元只有在兴奋状态时才会向下传送信号,所以WA了1次。
第二题:侦探推理
模拟+枚举
我用的是比较笨拙的枚举策略:枚举哪些人说的是真话,哪些人说的是假话。
但更好的策略是:枚举谁是凶手。
繁琐但不难,注意几个点:
- 凶手只有一个。那么当只有一个人且根据其话语无法推出是不是凶手时,其必然是凶手;
- 程序无法确定出凶手时可能是Cannot Determine,也可能是Impossible,需要根据具体情境进行特殊处理。
花了很久才AC,与我的解题策略的选择有莫大的关系。
第三题:加分二叉树
动态规划
很可惜做这道题在最开始的时候就想错了,用贪心写了一下,结果只过了1个点。应该说很多题目都是看似可以用贪心做但其实应该用动规(01背包、石子合并等),这也是以后做题时的一个注意点。
首先题目要求构造的树的中序遍历要有序,其实也就是由序列(1,2,…,n)构造出一棵二叉排序树:选择某个数字为根,把比它小的数字安排在它的左子树,把比它大的数安排在它的右子树,递归进行。
问题就是如何选择根?
由题意可以看出,一个数字的层次越深,它对整个二叉树的加分的「贡献」就越大,所以我想到的是贪心策略:将权值大的结点尽量安排在树的叶端,即把权值最小的结点作为根。
这样的贪心策略看似正确而且也符合样例数据,但其实是错误的。根据上面所述,如果按照贪心策略构建出这样的树,那么最理想的状态是结点的权值与深度应该成正比(但是为了满足BST的性质需要进行调整)。如果每次将权值最小的结点作为根,往往达不到这样的状态。比如:结点1,2,…,n对应的权值为99,2,2,…,2,则权值最大的结点1会被安排在权值最小的结点2的左子树而且成为叶子结点,这样分配明显是很不合理的。
正确的策略应该是采用动态规划,枚举需要用哪个结点作为根。
f(l, r) 表示将区间 [l, r] 构建成加分二叉树所得的最大加分(区间 [l, r] 表示结点编号),则
f(l, r) = max{ f(l, j) * f(j+1, r) + w(j), l<=j<=r}
边界条件:f(l, r) = 1 (l > r)
时间复杂度:O(n^3)
第四题:传染病控制
搜索
一开始以为是动规,但实际上有后效性。
按层进行搜索,枚举哪一条边需要被截断,将已被阻断的子树上的结点做标记,然后搜索下一层。
有一个普通的剪枝:如果当前感染人数大于已找到的最小人数则回溯。
但是很奇怪的是只有一个点过不了,而且答案只和标准答案相差1,实在无力调试,所以就针对特殊情况打表骗了个AC。
经验教训:
- 要总结平时遇到的容易想错算法的题目(动规想成贪心、搜索想成动规),寻找其特点与规律;
- 多做题目就会对各种算法适用的题型有更清晰的认识和更深刻的理解,帮助解题;
- 不能轻视模拟题,有些模拟题题目较复杂,要有提炼题目的能力。