疫情控制
(blockade.cpp/c/pas)
【问题描述】
H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点。
H 国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。
现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。
请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。
【输入】
输入文件名为 blockade.in。
第一行一个整数 n,表示城市个数。
接下来的 n-1 行,每行 3 个整数,u、v、w,每两个整数之间用一个空格隔开,表示从城市 u 到城市 v 有一条长为 w 的道路。数据保证输入的是一棵树,且根节点编号为 1。
接下来一行一个整数 m,表示军队个数。
接下来一行 m 个整数,每两个整数之间用一个空格隔开,分别表示这 m 个军队所驻扎的城市的编号。
【输出】
输出文件为 blockade.out。
共一行,包含一个整数,表示控制疫情所需要的最少时间。如果无法控制疫情则输出-1。
【输入输出样例说明】
第一支军队在 2 号点设立检查点,第二支军队从 2 号点移动到 3 号点设立检查点,所需时间为 3 个小时。
【数据范围】
保证军队不会驻扎在首都。
对于 20%的数据,2≤ n≤ 10;
对于 40%的数据,2 ≤n≤50,0<w <10 5 ;
对于 60%的数据,2 ≤ n≤1000,0<w <10 6 ;
对于 80%的数据,2 ≤ n≤10,000;
对于 100%的数据,2≤m≤n≤50,000,0<w <10 9 。

正解:贪心+二分答案+倍增

解题报告:

  写每年NOIP的T3找感觉。。。

  这道题开始觉得很码农,打完之后发现也就那样。。。网上题解讲的并不是很清楚,我详细讲一讲吧。

  这题还是运用一些比较神奇的东西。题意求一个最大值的最小值,我居然第一眼没看出来二分答案,显然直接二分一个时间,然后判断是否可行。

  考虑如何判断可行,得到一个时间之后,我们就可以知道所有军队是否能到达1号(首都),也就是根结点,为了很快求出来我们需要预处理一下距离,倍增自然最好。我们不妨对于每一支军队都算一下是否可以到达根结点,不能的话就记录一下最多能跳到哪里。对于这道题,我们可以很明显地看出越往上越优,所以我们对于不能到达根的就尽可能地往上跳,到他能达到的最高结点,打上标记,表示这个结点可以到达。然后我们就dfs一遍,自下往上判断一下,如果一个结点的所有儿子都已经存在封锁到叶子结点的距离了,那么这个结点也意味着封锁了,往上update就可以了。

  接下来我们统计一下根结点的所有儿子结点,那些已经封锁边境的我们肯定不需要再管了,已经可以覆盖了。我们只要考虑尚未封锁的,显然对于每个儿子结点,若想封闭这个儿子结点到边境,最优的肯定是直接封锁这个儿子结点。所以我们可以考虑对于那些可以到达根结点的军队,把他们派往各个未被封锁的儿子结点。当然,如果可派出的军队数如果还没有未封锁的儿子结点数量多,那么无论如何不可行。

  我们现在就有一些军队到达根结点之后剩余的行动时间和每个未被封锁的儿子结点到根结点的距离。我们需要将他们进行匹配,也就是把军队派往各地。首先,我们必须明确,如果某只军队可以到达根结点,而他所在的根结点的儿子结点的那棵树中,不妨设为root,肯定把他直接派往root驻扎即可,因为把他派往别的未被封锁的城市的话,还需要另外调军队过来驻扎这个root,肯定不会更优,具体证明略。

  综上,我们的判断做法就是:军队按剩余时间排序,未被封锁的儿子结点按到根结点距离排序,而每支军队如果他的root未被封锁,则直接派往root,否则选择一个距离最近的未被封锁的儿子结点,前往驻扎,因为如果最近的都无法派往的话,这支军队就不能发挥任何作用了。(这是一个经典的O(N)匹配。。。)

  就这么做啦,代码如下:

  1. //It is made by jump~
  2. #include <iostream>
  3. #include <cstdlib>
  4. #include <cstring>
  5. #include <cstdio>
  6. #include <cmath>
  7. #include <algorithm>
  8. #include <ctime>
  9. #include <vector>
  10. #include <queue>
  11. #include <map>
  12. #include <set>
  13. using namespace std;
  14. typedef long long LL;
  15. const int MAXN = ;
  16. LL inf;
  17. int n,m,ecnt,a[MAXN];
  18. int root[MAXN];//属于根结点的哪个子结点
  19. int next[MAXN*],to[MAXN*],first[MAXN],w[MAXN*];
  20. int f[MAXN][];
  21. LL g[MAXN][];
  22. LL l,r,ans,mid;
  23. bool pd[MAXN];
  24. struct node{
  25. LL remain;
  26. int root;
  27. }b[MAXN];
  28. struct son{
  29. LL dis;
  30. int pos;
  31. }c[MAXN];
  32.  
  33. inline int getint()
  34. {
  35. int w=,q=; char c=getchar();
  36. while((c<'' || c>'') && c!='-') c=getchar(); if(c=='-') q=,c=getchar();
  37. while (c>='' && c<='') w=w*+c-'', c=getchar(); return q ? -w : w;
  38. }
  39.  
  40. inline bool cmp(node q,node qq){ return q.remain<qq.remain; }
  41. inline bool ccmp(son q,son qq){ return q.dis<qq.dis; }
  42.  
  43. inline void dfs(int x,int fa){
  44. for(int i=first[x];i;i=next[i]) {
  45. int v=to[i]; if(v==fa) continue;
  46. if(x==) root[v]=v; else root[v]=root[x];
  47. dfs(v,x); f[v][]=x; g[v][]=w[i];
  48. }
  49. }
  50.  
  51. inline void dfs2(int x,int fa){
  52. bool flag=false,ff=true;
  53. for(int i=first[x];i;i=next[i]) {
  54. int v=to[i]; if(v==fa) continue;
  55. flag=true; dfs2(v,x);
  56. if(!pd[v]) ff=false;
  57. }
  58. if(ff && flag && x!=) pd[x]=;
  59. }
  60.  
  61. inline bool check(LL limit){
  62. int u; LL total;
  63. int cnt=; memset(pd,,sizeof(pd));
  64. for(int i=;i<=m;i++) {
  65. u=a[i]; total=limit;
  66. for(int j=;j>=;j--) {
  67. if(total>=g[u][j] && f[u][j]!=) {
  68. total-=g[u][j];
  69. u=f[u][j];
  70. }
  71. }
  72. if(u==) {
  73. b[++cnt].remain=total;
  74. b[cnt].root=root[a[i]];
  75. }
  76. else pd[u]=;
  77. }
  78.  
  79. dfs2(,);//处理跳到一半到达不了根的情况,往上update,注意顺序!!!
  80.  
  81. ecnt=;//统计根结点的未被覆盖的儿子个数
  82. for(int i=first[];i;i=next[i]) {
  83. if(pd[to[i]]) continue;//统计未被覆盖的!!!
  84. c[++ecnt].pos=to[i];
  85. c[ecnt].dis=w[i];
  86. }
  87.  
  88. if(ecnt>cnt) return false;
  89. sort(b+,b+cnt+,cmp); sort(c+,c+ecnt+,ccmp);
  90. int now=;//当前处理到的根结点的儿子结点
  91. c[ecnt+].dis=inf;
  92. for(int i=;i<=cnt;i++) {
  93. if(!pd[b[i].root]) pd[b[i].root]=; //当前军队处在这个儿子结点尚未被覆盖,那么直接派遣他过去驻扎就可以了
  94. else {
  95. while(pd[c[now].pos]) now++;
  96. if(b[i].remain>=c[now].dis) pd[c[now].pos]=,now++;
  97. }
  98. while(pd[c[now].pos]) now++;
  99. }
  100. if(now>ecnt) return true;
  101. return false;
  102. }
  103.  
  104. inline void work(){
  105. n=getint(); int x,y,z;
  106. for(int i=;i<n;i++) {
  107. x=getint(); y=getint(); z=getint();
  108. next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; w[ecnt]=z;
  109. next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x; w[ecnt]=z;
  110. }
  111. m=getint(); for(int i=;i<=m;i++) a[i]=getint();
  112. dfs(,);
  113. for(int j=;j<=;j++)//注意倍增细节,更新顺序!!!
  114. for(int i=;i<=n;i++){
  115. f[i][j]=f[f[i][j-]][j-];
  116. g[i][j]=g[f[i][j-]][j-]+g[i][j-];
  117. }
  118. inf=; for(int i=;i<=;i++) inf*=;
  119. l=; r=inf;
  120. if(!check(r)) { printf("-1"); return ; }
  121. while(l<=r) {
  122. mid=(l+r)/;
  123. if(check(mid)) ans=mid,r=mid-;
  124. else l=mid+;
  125. }
  126. printf("%lld",ans);
  127. }
  128.  
  129. int main()
  130. {
  131. work();
  132. return ;
  133. }

codevs1218 疫情控制的更多相关文章

  1. Codevs 1218 疫情控制 2012年NOIP全国联赛提高组

    1218 疫情控制 2012年NOIP全国联赛提高组 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description H 国有 n 个城市,这 ...

  2. 【NOIP2012】 疫情控制

    [NOIP2012] 疫情控制 标签: 倍增 贪心 二分答案 NOIP Description H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树, 1 号城市是首都, 也是 ...

  3. Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增)

    Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增) Description H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树, 1 号城市是首都, 也是 ...

  4. [NOIP2012]疫情控制 贪心 二分

    题面:[NOIP2012]疫情控制 题解: 大体思路很好想,但是有个细节很难想QAQ 首先要求最大时间最小,这种一般都是二分,于是我们二分一个时间,得到一个log. 然后发现一个军队,越往上走肯定可以 ...

  5. 疫情控制 blockade

    疫情控制 blockad 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树, 1 号城市是首都, 也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当 ...

  6. 疫情控制 2012年NOIP全国联赛提高组(二分答案+贪心)

    P1084 疫情控制 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控 ...

  7. CH6301 疫情控制

    6301 疫情控制 0x60「图论」例题 描述 H国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病. ...

  8. luoguP1084 疫情控制(题解)(搜索+贪心)

    luoguP1084 疫情控制 题目 #include<iostream> #include<cstdlib> #include<cstdio> #include& ...

  9. 洛谷P1084 [NOIP2012提高组Day2T3]疫情控制

    P1084 疫情控制 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控 ...

随机推荐

  1. centos7 改变终端背景色

    首先打开终端 2:选择 edit->preferences->profile 3: "model1"是我自己改的名字,最开始是"unname".双击 ...

  2. 查看Android源码和源码布局

    一.查看源码 1.https://github.com/android 2.http://grepcode.com/project/repository.grepcode.com/java/ext/c ...

  3. java -cp 命令 java jar 命令和 hadoop jar 命令

     -cp 和 -classpath 一样,是指定类运行所依赖其他类的路径,通常是类库,jar包之类,需要全路径到jar包,window上分号“;”  java -cp .;myClass.jar pa ...

  4. 《Lucene in Action 第二版》第三章节的学习总结----IndexSearcher以及Term和QueryParser

    本章节告诉我们怎么用搜索.通过这章节的学习,虽然搜索的内部原理不清楚,但是至少应该学会简单的编写搜索程序了本章节,需要掌握如下几个主要API1.IndexSearcher类:搜索索引的门户,发起者. ...

  5. RabbitMQ集群安装配置+HAproxy+Keepalived高可用

    RabbitMQ集群安装配置+HAproxy+Keepalived高可用 转自:https://www.linuxidc.com/Linux/2016-10/136492.htm rabbitmq 集 ...

  6. 你可能不知道的5个功能强大的 HTML5 API

    HTML5 新增了许多重要的特性,像 video.audio 和 canvas 等等,这些特性使得能够很容易的网页中包含多媒体内容,而不需要任何的插件或者 API.而其它的新元素,例如 section ...

  7. windows10系统自带输入法不能切换中文如何解决

    具体如下: 1.打开计算机管理软件,右击“开始”按钮,在弹出的菜单中选择“计算机管理”: 2.或在桌面右击“此电脑”图标,在弹出的菜单中选择“管理”: 3.在打开的计算机管理软件中,选择“系统工具”- ...

  8. vim对光标所在的数字进行增减

    真是vim会在不经意间给你惊喜...... 现在发现把光标移到某数字的上方,c-a是加1, c-x是减1 当时真有点众里寻他千百度的感觉

  9. effect request

    from bs4 import BeautifulSoup import os filepath = 'D:\\pymine\\clean\\spider_map\\baidu_map_html_fi ...

  10. 经典的css reset代码 (reset.css)

    <style> html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, ...