疫情控制
(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. POJ1195 Mobile phones 【二维线段树】

    Mobile phones Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 14291   Accepted: 6644 De ...

  2. Shader编程教程

    2010-05-13 11:37:14|  分类: DirectX 3D学习|举报|字号 订阅     Shader编程教程1-环境光照 您好,欢迎来到XNA Shader教程1.我的名字叫Petri ...

  3. 篇章一:[AngularJS] 使用AngularAMD動態載入Controller

    前言 使用AngularJS來開發Single Page Application(SPA)的時候,可以選用AngularUI Router來提供頁面內容切換的功能.但是在UI Router的使用情景裡 ...

  4. MBA人物俞洪敏:亿万富翁的生活表

    我的智商非常一般,就是比别人勤奋.我的脑袋不属于特别笨的那种,但肯定也不是顶尖聪明的类型.在北大的50个同学当中,我的智商应该属于中下水平,这说明我不是顶尖高智商. 我的勤奋一般人跟不上.我平均每天工 ...

  5. cobbler+koan

    cobbler+koan自动重装客户机   koan是kickstart-over-a-network的缩写,它是cobbler的客户端帮助程序,koan允许你通过网络提供虚拟机,也允许你重装已经存在 ...

  6. 嵌入式开发之davinci--- 8127 中osd yuv 数据分析

    YUV数据类型总结: YUV格式有两大类:planar和packed.对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V.对于packed的YUV格 ...

  7. JMeter 通过CSV Data Set Config 中文参数化数据,插入数据库后中文显示乱码,解决办法

    问题描述: 1. 需要设置中文参数化,模拟post请求,通过配置元件 - CSV Data Set Config 进行设置. 2. 数据库数据显示乱码(实际数据为 “测试001”) 解决办法: CSV ...

  8. 【BZOJ3993】[SDOI2015]星际战争 二分+最大流

    [BZOJ3993][SDOI2015]星际战争 Description 3333年,在银河系的某星球上,X军团和Y军团正在激烈地作战.在战斗的某一阶段,Y军团一共派遣了N个巨型机器人进攻X军团的阵地 ...

  9. unix网络编程笔记(二)

    第四章笔记 1. 基本Tcpclient/server程序的套接字函数 2. socket函数: int socket(int family,int type,int protocol); (1)so ...

  10. Linux中源码包安装

    1.准备环境 a.因为是编译安装,所以需要安装gcc编译器 b.下载源码包 2.注意事项 a.源代码保存位置 /usr/local/src/ b.软件安装位置 /usr/local/ c.如何确定安装 ...