zoukankan      html  css  js  c++  java
  • 校内题目锦鲤抄

    v>

    3.锦鲤抄
    (zay.cpp/c) 【题目背景】
    你在尘世中辗转了千百年
    却只让我看你最后一眼
    火光描摹容颜燃尽了时间
    别留我一人,孑然一身
    凋零在梦境里面。
    ——银临&云の泣《锦鲤抄》
    【问题描述】
    这首歌的文案讲述了这样一个故事:
    在一个兵荒马乱的年代,有一位画师叫浅溪,非常喜欢画锦鲤。战火烧到了泰
    安,他的邻居都惊慌逃命,只有他不舍得池中锦鲤没有离开。这天晚上庭院失火,
    池中的锦鲤化妖,用生命护住了画师的平安。
    注意:由于本题题面涉及到文案故事,在下方提供了便于理解的另一题面版本。
    扶苏被画师和锦鲤的故事深深地打动了。为了能让锦鲤和画师继续生活在一起,他
    决定回到着火的庭院中灭掉大火。
    画师的庭院可以抽象成一个有向图,每个点代表着一个着火的位置。为了量化火势
    的大小,扶苏给每个点一个火力值,火力值越大,代表这个点的火势越强。风助火势,
    火借风力,对于每一个着火点,都有可能因为大风使得火扩散到其他点。有向图的每条
    边 <u,v> 代表大火是从点 u 扩散到点 v 的。需要注意的是一个点可能会扩散到很多
    点,也可能是由很多点的大火一起扩散成的。为了不因为灭掉火源让画师发现有人在帮
    他灭火,在任意时刻,扶苏不能灭掉任何一个不被任何点所扩散的点的火。一个点的火
    被灭掉后,所代表该点的火扩散的所有边将消失。需要说明的是,虽然边消失了,但是
    该点扩散到的所有点属性除入度以外都不会改变,更不会消失。
    因为穿越的时间有限,扶苏只能灭掉最多 k 个点的火。忙着写题面的扶苏没有时间
    算出他最多能扑灭多少火力值,于是他把这个问题交给了你。
    便于理解的题面版本:
    给你一张有向图,每个点有一个点权。你可以任意选择一个有入度的点,获得它的
    点权并把它和它的出边从图上删去。任意时刻不能选择没有入度的点。最多能选择 k 个
    点,求最多能获得多少点权。
    【输入格式】
    输入文件名为 zay.in。
    输入文件中有且仅有一组数据,第一行为三个正整数 n,m,k,代表有向图的点数、
    边数以及最多选择的点数。
    第二行有 n 个整数,第 i 个整数代表节点 i 的火力值(点权)
    下面 m 行,每行两个正整数 u,v,代表大火是从 u 扩散到 v 的,即有向图的边。
    v>
    【输出格式】
    输出文件名为 zay.out。
    输出一行一个正整数,代表答案。
    【输入输出样例 1】
    zay.in zay.out
    7 7 3 24
    10 2 8 4 9 5 7
    1 2
    1 3
    1 4
    2 5
    3 6
    3 7
    4 7见选手文件夹下的 Samples/zay/zay1.in 和 Samples/zay/zay1.ans。
    【样例1 解释】
    样例一如左图。
    所选择的点为 3,5,7 三个节点,
    所获得的火力值之和为 8+9+7=24.
    可以证明这是最优的方案。
    【输入输出样例 2】
    见选手文件夹下的 Samples/zay/zay2.in 和 Samples/zay/zay2.ans。
    【数据规模与约定】
    本题共 5 个子任务,捆绑测试,各子任务不等分。各子任务的数据性质如下表
    子任务编号 n= m= 特殊性质 子任务分数
    1 10 50 特殊性质1 5
    2 11 51 无 25
    3 100002 500002 特殊性质2 30
    4 100003 100003 无 35
    5 1000004 5000004 无 5
    对于100%的数据,保证0≤给出的点权≤1000,0≤k≤n
    特殊性质1:保证给出的点权一定为 0
    特殊性质2:保证给出的图是一个有向无环图
    v>
    【提示】
    1、本题输入量极大,请注意大数据的读入对程序效率造成的影响
    2、根据 n 和 m 的末位数字可以帮助你快速的判断子任务类型以及特殊性质。
    3、本题进行捆绑测试,如果你不知道什么叫捆绑测试,请阅读选手文件夹下的选手
    须知。
     

    题解:

    v>

    子任务 1:
    点权都是0,于是无论怎么选答案都是 0,输出 0 即可。期望得分 5 分。
    子任务 2:
    爆搜,枚举所有可能的顺序,然后计算答案。
    由于保证了数据随机,可以在搜索的过程中进行剪枝,效率很高,期望得分25
    分。
    子任务 3:
    给出的是一个 DAG 。考虑对于一个 DAG 来说,一个良好的的性质就是在拓扑
    序后面的点无论如何变化都无法影响到前面的点。这个题也一样。对于任意一个不
    出现原图中本身入度为 0 的点的序列,只要按照拓扑序选点,就一定能取遍序列中
    所有的点。
    于是发现这张图上入度不为0的点事实上都可以被选择。于是我们把所有入度不
    为0的点排一下序,求前k个就可以了。时间复杂度 O(nlogn),期望得分30
    子任务 4、5:
    考虑DAG的情况放到普通有向图上会发生什么。
    有了子任务 3 的提示,我们可以考虑把整个图缩点,将其变成一个DAG来做。
    对于一个DAG,显然可以通过子任务 3 调整顺序的方式使得每个强连通分量的
    选择情况除选点个数以外互不影响。故下面只讨论一个强连通分量内部的情况。
    一个强连通分量显然可以看作是一棵外向树加上很多边得到的。
    一棵外向树的定义:一个外向树的任意一个节点要么为叶节点,要么它与孩子
    间的所有边都是由它指向孩子。
    一棵外向树显然是一个 DAG 。按照之前对 DAG 上情况的说明,显然我们可以
    选择除了根节点以外的任意节点。
    因为一个强连通分量内部是互相连通的,于是我们不妨钦定一个点为根。
    对于一个没有入度的强连通分量,我们不妨钦定点权最小的点为根。这样显然
    选择的是最优的。
    对于一个有入度的强连通分量,我们不妨钦定那个有入度的点为根。这样在选
    择到只剩根节点的时候,因为根节点有入度,所以根节点是可以被选择的。于是这
    个强连通分量可以被全部选择。这显然是最优的。
    这样综合上述讨论,有入度的强连通分量可以随便选,没有入度的强连通分量
    去掉最小的点权的点。剩下贪心取前 k 个就可以了。
    进行一次 tarjan的复杂度是 O(n+m),选前 k 个点可以排序一下。这样总复杂
    度 O(m+nlogn),期望得分 35 分。注意到复杂度瓶颈在排序上,考虑我们只需要前
    k 大而不需要具体前 k 个之间的大小关系,于是使用 std::nth_element()函数可
    以将复杂度降至 O(n+m)。期望得分 40 分。注意,输入规模到了 10
    7
    级别,需要
    fread 来实现读入优化。
  • 相关阅读:
    JavaScript面试题
    HTML&&css面试题
    nodejs面试题
    linux上安装apache
    linux上安装mysql
    linux基础命令学习(三)Vim使用
    linux基础命令学习(一)
    spring学习(六)注解方式实现AOP
    spring学习(五)详细介绍AOP
    spring学习(一)spring简介
  • 原文地址:https://www.cnblogs.com/lbssxz/p/11073372.html
Copyright © 2011-2022 走看看