疫情控制
(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)匹配。。。)

  就这么做啦,代码如下:

 //It is made by jump~
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
using namespace std;
typedef long long LL;
const int MAXN = ;
LL inf;
int n,m,ecnt,a[MAXN];
int root[MAXN];//属于根结点的哪个子结点
int next[MAXN*],to[MAXN*],first[MAXN],w[MAXN*];
int f[MAXN][];
LL g[MAXN][];
LL l,r,ans,mid;
bool pd[MAXN];
struct node{
LL remain;
int root;
}b[MAXN];
struct son{
LL dis;
int pos;
}c[MAXN]; inline int getint()
{
int w=,q=; char c=getchar();
while((c<'' || c>'') && c!='-') c=getchar(); if(c=='-') q=,c=getchar();
while (c>='' && c<='') w=w*+c-'', c=getchar(); return q ? -w : w;
} inline bool cmp(node q,node qq){ return q.remain<qq.remain; }
inline bool ccmp(son q,son qq){ return q.dis<qq.dis; } inline void dfs(int x,int fa){
for(int i=first[x];i;i=next[i]) {
int v=to[i]; if(v==fa) continue;
if(x==) root[v]=v; else root[v]=root[x];
dfs(v,x); f[v][]=x; g[v][]=w[i];
}
} inline void dfs2(int x,int fa){
bool flag=false,ff=true;
for(int i=first[x];i;i=next[i]) {
int v=to[i]; if(v==fa) continue;
flag=true; dfs2(v,x);
if(!pd[v]) ff=false;
}
if(ff && flag && x!=) pd[x]=;
} inline bool check(LL limit){
int u; LL total;
int cnt=; memset(pd,,sizeof(pd));
for(int i=;i<=m;i++) {
u=a[i]; total=limit;
for(int j=;j>=;j--) {
if(total>=g[u][j] && f[u][j]!=) {
total-=g[u][j];
u=f[u][j];
}
}
if(u==) {
b[++cnt].remain=total;
b[cnt].root=root[a[i]];
}
else pd[u]=;
} dfs2(,);//处理跳到一半到达不了根的情况,往上update,注意顺序!!! ecnt=;//统计根结点的未被覆盖的儿子个数
for(int i=first[];i;i=next[i]) {
if(pd[to[i]]) continue;//统计未被覆盖的!!!
c[++ecnt].pos=to[i];
c[ecnt].dis=w[i];
} if(ecnt>cnt) return false;
sort(b+,b+cnt+,cmp); sort(c+,c+ecnt+,ccmp);
int now=;//当前处理到的根结点的儿子结点
c[ecnt+].dis=inf;
for(int i=;i<=cnt;i++) {
if(!pd[b[i].root]) pd[b[i].root]=; //当前军队处在这个儿子结点尚未被覆盖,那么直接派遣他过去驻扎就可以了
else {
while(pd[c[now].pos]) now++;
if(b[i].remain>=c[now].dis) pd[c[now].pos]=,now++;
}
while(pd[c[now].pos]) now++;
}
if(now>ecnt) return true;
return false;
} inline void work(){
n=getint(); int x,y,z;
for(int i=;i<n;i++) {
x=getint(); y=getint(); z=getint();
next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; w[ecnt]=z;
next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x; w[ecnt]=z;
}
m=getint(); for(int i=;i<=m;i++) a[i]=getint();
dfs(,);
for(int j=;j<=;j++)//注意倍增细节,更新顺序!!!
for(int i=;i<=n;i++){
f[i][j]=f[f[i][j-]][j-];
g[i][j]=g[f[i][j-]][j-]+g[i][j-];
}
inf=; for(int i=;i<=;i++) inf*=;
l=; r=inf;
if(!check(r)) { printf("-1"); return ; }
while(l<=r) {
mid=(l+r)/;
if(check(mid)) ans=mid,r=mid-;
else l=mid+;
}
printf("%lld",ans);
} int main()
{
work();
return ;
}

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. C++中没有定义类的引用。

    在有时候由于类太大.须要在类在后面定义: 比如: class Y{ void f(X); }; class X{ //一些成员数据和函数 }; //error 由于c++要求不论什么一个变量在引用之前 ...

  2. jfreechart折线图 demo

    public class ChartUtil { public static ChartUtil chartUtil; private RoomViewsDataService roomViewsDa ...

  3. Apache中KeepAlive 配置

    引子 先来分析一个Yslow 测试的一个页面的前端性能. 这里所有的请求是指http请求,对于一个请求各个阶段的划分,阻挡->域名解析->建立连接->发送请求->等待响应-&g ...

  4. 为什么Goroutine能有上百万个,Java线程却只能有上千个?

      作者|Russell Cohen   译者|张卫滨   本文通过 Java 和 Golang 在底层原理上的差异,分析了 Java 为什么只能创建数千个线程,而 Golang 可以有数百万的 Go ...

  5. 每天学习30分钟新知识之html教程1

    版本 年份 HTML 1991 HTML+ 1993 HTML 2.0 1995 HTML 3.2 1997 HTML 4.01 1999 XHTML 1.0 2000 HTML5 2012 XHTM ...

  6. nginx(Window下安装 & 配置文件参数说明 & 实例)

    一.为什么需要对Tomcat服务器做负载均衡:  Tomcat服务器作为一个Web服务器,其并发数在300-500之间,如果有超过500的并发数便会出现Tomcat不能响应新的请求的情况,严重影响网站 ...

  7. 【BZOJ2724】[Violet 6]蒲公英 分块+二分

    [BZOJ2724][Violet 6]蒲公英 Description Input 修正一下 l = (l_0 + x - 1) mod n + 1, r = (r_0 + x - 1) mod n ...

  8. config相关操作(转)

    转自:http://www.cnblogs.com/kissdodog/archive/2013/04/16/3025315.html,这是一个专题,感觉比较好,有空可以看与一下 System.Con ...

  9. Convex optimization 凸优化

    zh.wikipedia.org/wiki/凸優化 以下问题都是凸优化问题,或可以通过改变变量而转化为凸优化问题:[5] 最小二乘 线性规划 线性约束的二次规划 半正定规划 Convex functi ...

  10. Redis的主从同步手动执行故障切换

    1.准备三个redis配置文件,通过端口的区分,启动三个redis数据库实例,然后配置主从复制. # a6371.conf port 6371 daemonize yes pidfile /data/ ...