zoukankan      html  css  js  c++  java
  • noip2010提高组题解

    第一题:机器翻译

    模拟

    可以用STL里的vector或list实现插入、删除、查找操作。

     

    第二题:乌龟棋

    动态规划

    用 f(i, j, k, t) 表示分别用了i张卡片1、j张卡片2、k张卡片3、t张卡片4能得到的最大分数,则

    f(i, j, k, t) = max{ f(i-1, j, k, t), f(i, j-1, k, t), f(i, j, k-1, t), f(i, j, k, t-1) } + a(i+j*2+k*3+t*4)

    因为题目保证sum(bi) = N-1,所以最终答案就是 f(i, j, k, t), i=card(1), j=card(2), k=card(3), t=card(4).

     

    第三题:关押罪犯

    二分枚举答案+二分图判定

    二分枚举答案和二分图都算是我的弱点,主要是因为接触的这种类型的题目不多。

    既然要求「最大值的最小值」,那么只要二分枚举冲突的最大值即可。两个牢房,身处不同的牢房的犯人之间不会起冲突,明显符合二分图的性质。所以,我们可以把「有边」看做「在不同牢房」,「无边」看做「在同一个牢房」。对于mid=(l+r)/2,删去比mid小的边,那么删去的这些边是实际上存在的冲突,然后判断是不是二分图即可。如果是,那么记录下mid,然后改变枚举范围,令r=mid,继续枚举看有没有更小的满足条件的mid值;如果不是,令l=mid+1,继续枚举。

    枚举有两种方法,一种是直接枚举mid的大小,另一种是在排好序的边集数组中进行枚举。第一种方法有一些无效枚举,也就是说中间过程枚举得到的值并不真实存在于图中,那么枚举次数最多log(ci)≈30;第二种方法需要进行排序,但是枚举次数最多log(M)≈17。总体来看效率差不多。

    并查集

    这种方法效率更高。

    按照怨气的大小依次放入两个集合中,保持集合内部不冲突,直到同一个集合内产生冲突,输出即可。

     

    第四题:引水入城

    贪心、搜索、动态规划

    这道题有多种解法,先说我自己的思路。

    思路一:我最开始的做法是在第一行找出最大的,进行 Flood Fill 填充直到底行;然后找出第二大的,填充……直到能够将底行填满。该策略基于这样一个臆测:第一行里较大的数字总是能够填充到较多的底行格子。但是这样做明显不正确。

    思路二:对第一行的每个格子进行 Flood Fill,找出每个顶行格子能够填充到的底行格子是哪些,第 i 个顶部格子所能达到的底部格子的集合记为B(i)。选出元素数目最大的集合Bmax,进行填充,然后调整B(i),即删去{x | x∈Bmax∩B(i) },因为如果格子已经被填充,那么将它记入元素数目中就没有意义了,也就是说元素数目 card(B(i)) 表示如果从顶部格子 i 开始填充,那么能够填充多少个未被填充的底部格子。

    思路三:思路二已经有一大半正确了,但不完全正确。事实上这里不能用贪心策略,而应该用搜索。这种情况有点像2000年提高组的「单词接龙」一题,贪心策略是错误的,因为每次决策不能只依赖于上一次的状态,而是由之前所有的决策决定的,所以也不能用动态规划(如果沿用上面的这种思路)。

    虽然找到了正确思路但是实现起来太过麻烦。上面的第二种思路已经可以拿到 80% 的分数了。如果要搜索,那么时间复杂度和编程复杂度都会陡增。

    (以下思路来自:http://www.cnblogs.com/vb4896/p/3885441.html

    更进一步

    1. 先用一次 BFS 判断是否无解。
    2. 在有解的情况下,可以证明每个蓄水厂能够覆盖的底部格子是一个连续的区间。(如果蓄水厂 a 能覆盖的最左和最右格子分别为 l, r,中间有一个无法覆盖的格子记作y,那么必然有另外一条路线 b->y 可以到达y,这条路线必然会与路线 x->l 或者路线 x->r 交叉,则 x 可以在交叉点处更换路线到达 y,与假设矛盾。)
    3. 既然是连续的区间,那么就转换为了线段覆盖问题,可以采用这样的贪心策略:每次选择能够将(从左到右数)第一个未覆盖的点覆盖、并且右端点最大的区间进行覆盖。
    4. 要求出每个蓄水厂能够覆盖的区间用 DFS 或 BFS,同上。

    应该说这样的策略已经很不错了,但还是会超时。

    再进一步

    用 left(i, j) 表示点 (i, j) 能覆盖的区间的左端点,right(i, j) 表示点 (i, j) 能覆盖的区间的右端点,则

    left(i, j) = min{ left(xi, xj), (xi, xj) 与 (i, j) 相邻且海拔低于 (i, j) }

    边界条件:left(i, j) = j,当且仅当 i=n-1, j=0

    注意:当 i=n-1 时,left(i, j) 的值不可能大于 j

    right(i, j) 同理。

    注意还是要用一次 BFS 判断是否无解。

     

    经验教训:

    1. 在考场上可以使用贪心骗分,但是一定要不断优化贪心策略增加得到正确答案的概率。
  • 相关阅读:
    Xcode常用
    iOS知识点
    iOS Crash上传
    [crash详解与防护] KVO crash
    iOS常见bug
    PHP实现万年历
    在Vue框架中引入Element
    PHP--随机生成颜色
    PHP读取Excel表格数据
    权限管理功能(一)
  • 原文地址:https://www.cnblogs.com/lsdsjy/p/3886733.html
Copyright © 2011-2022 走看看