洛谷 P1084 疫情控制 题解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P1084 疫情控制 题解相关的知识,希望对你有一定的参考价值。

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。

题目链接:https://www.luogu.org/problem/show?pid=1084

题目描述

H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点。

H 国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。

现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。

请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。

输入输出格式

输入格式:

第一行一个整数 n,表示城市个数。

接下来的 n-1 行,每行 3 个整数,u、v、w,每两个整数之间用一个空格隔开,表示从城市 u 到城市 v 有一条长为 w 的道路。数据保证输入的是一棵树,且根节点编号为 1。

接下来一行一个整数 m,表示军队个数。

接下来一行 m 个整数,每两个整数之间用一个空格隔开,分别表示这 m 个军队所驻扎的城市的编号。

输出格式:

共一行,包含一个整数,表示控制疫情所需要的最少时间。如果无法控制疫情则输出-1。

输入输出样例

输入样例#1:
4 
1 2 1 
1 3 2 
3 4 3 
2 
2 2
输出样例#1:
3

说明

【输入输出样例说明】

第一支军队在 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 2012 提高组 第二天 第三题

 

分析:

在树上二分答案+贪心。贪心思路应该不算太难吧就是代码好长好麻烦..._(:з」∠)_

对于一支军队:如果它能到达根节点 - 贪心地选择是让它到达根节点下的直系儿子,还是越过根节点封锁其他的点

如果它不能到达根节点 - 让它尽量向上走,也就是尽量封锁更多的点

安利朋友的博客

 

AC代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<iostream>
  6 
  7 const int MAXN = 50005;
  8 inline void read(int &x)
  9 {
 10     char ch = getchar(),c = ch;x = 0;
 11     while(ch < 0 || ch > 9) c = ch,ch = getchar();
 12     while(ch <= 9 && ch >= 0) x = (x<<1)+(x<<3)+ch-0,ch = getchar();
 13     if(c == -) x = -x;
 14 }
 15 
 16 int n,m,u,v,w,cnt,rscnt,cntar,cntct;
 17 int head[MAXN<<1],army[MAXN],son[MAXN];
 18 //son记录每个节点的子节点数量 
 19 int cover_effect[MAXN],cover[MAXN],from[MAXN],rtson[MAXN];
 20 //cover_effect表示覆盖当前节点是否等价于覆盖该节点的父节点
 21 //cover记录某个点是否被覆盖,from记录某个点的父节点是谁
 22 //rtson记录根节点的直系子节点 
 23 int f[MAXN][21],g[MAXN][21],restep[MAXN],pos[MAXN];
 24 //f[i][j]表示从i向上跳2^j步到达的节点
 25 //g[i][j]表示从i跳到向上2^j步的祖先的距离 
 26 //restep记录某个点到达根节点之后还能走的距离
 27 //pos表示军队最终停留的位置 
 28 long long l,mid,r,ans;
 29 
 30 struct Edge
 31 {
 32     int f,t,v,nxt;
 33 }e[MAXN<<1];
 34 
 35 void insert(int f,int t,int v)
 36 {
 37     e[++cnt].f = f,e[cnt].t = t;
 38     e[cnt].v = v,e[cnt].nxt = head[f];
 39     head[f] = cnt;
 40 }
 41 
 42 void init_dfs(int u)
 43 {//预处理出f数组和g数组. 
 44     if(f[u][0] == 1) from[u] = u;
 45     else from[u] = from[f[u][0]];
 46     
 47     for(int i = head[u];i;i = e[i].nxt)
 48     {
 49         int v = e[i].t;
 50         if(u == 1) rtson[++rscnt] = v;
 51         if(v == f[u][0]) continue;
 52         son[u] ++;
 53         f[v][0] = u,g[v][0] = e[i].v;
 54         
 55         init_dfs(v);
 56     }
 57 }
 58 
 59 void dfs(int u)
 60 {
 61     cover_effect[u] = 1;
 62     if(son[u] > 1) return;
 63     for(int i = head[u];i;i = e[i].nxt)
 64         if(e[i].t != f[u][0])
 65             dfs(e[i].t);
 66 }
 67 
 68 void init()
 69 {//计算f数组和g数组 
 70     for(int i = 1;i <= rscnt;++ i)
 71         dfs(rtson[i]);
 72     for(int j = 1;(1<<j) <= n;++ j)
 73         for(int i = 1;i <= n;++ i)
 74         {
 75             f[i][j] = f[f[i][j-1]][j-1];
 76             g[i][j] = g[i][j-1]+g[f[i][j-1]][j-1];
 77         }
 78 }
 79 
 80 struct ARMY
 81 {
 82     int restep,from;
 83 }A[MAXN];
 84 
 85 struct CITY
 86 {
 87     int id,dis;
 88     //dis是与根节点的距离 
 89 }B[MAXN];
 90 
 91 int cmp1(ARMY a,ARMY b)
 92 {return a.restep < b.restep;}
 93 
 94 int cmp2(CITY a,CITY b)
 95 {return a.dis < b.dis;}
 96 
 97 void calc(int u)
 98 {
 99     long long tmp = mid;
100     pos[u] = army[u];
101     int M = 0;
102     for(;(1<<M)<=n;++M);-- M;
103     for(int i = M;i >= 0;-- i)
104     {//让军队尽量向上走 
105         if(tmp >= g[pos[u]][i] && f[pos[u]][i] != 0)
106         {
107             tmp -= g[pos[u]][i];
108             pos[u] = f[pos[u]][i];
109         }
110     }
111     restep[u] = tmp;
112 }
113 
114 bool jud(long long x)
115 {
116     memset(cover,0,sizeof(cover));
117     cntar = cntct = 0;
118     for(int i = 1;i <= m;++ i)
119     {
120         calc(i);
121         if(pos[i] != 1){
122             //无法到达根节点的军队 
123             if(cover_effect[pos[i]])
124                 cover[from[pos[i]]] = 1;
125         }
126         else{
127             //能够到达根节点的军队 
128             cntar ++;
129             A[cntar].restep = restep[i];
130             A[cntar].from = from[army[i]];
131         }    
132     }
133     for(int i = 1;i <= rscnt;++ i)
134     {
135         if(!cover[rtson[i]])
136         {
137             cntct ++;
138             B[cntct].id = rtson[i];
139             B[cntct].dis = g[rtson[i]][0];
140         }
141     }
142     if(cntct > cntar) return 0;
143     std::sort(A+1,A+1+cntar,cmp1);
144     std::sort(B+1,B+1+cntct,cmp2);
145     int i = 1,j = 1;
146     while(i <= cntar)
147     {//尝试用军队覆盖每一个未被覆盖的城市 
148         if(!cover[A[i].from])
149             cover[A[i].from] = 1;
150         else
151         {
152             while(j <= cntct && cover[B[j].id]) ++ j;
153             if(B[j].dis <= A[i].restep) cover[B[j].id] = 1,++ j;
154         }
155         ++ i;
156     }
157     for(int i = 1;i <= cntct;++ i)
158         if(!cover[B[i].id]) return 0;
159     return 1;
160 }
161 
162 int main()
163 {
164 //    freopen("1.txt","r",stdin);
165     read(n);
166     for(int i = 1;i < n;++ i)
167     {
168         read(u),read(v),read(w);
169         r += w;
170         insert(u,v,w);
171         insert(v,u,w);
172     }
173     read(m);
174     for(int i = 1;i <= m;++ i)
175         read(army[i]);
176     init_dfs(1);
177     if(rscnt > m){
178         printf("-1\\n");
179         return 0;
180     }
181     init();
182     while(l <= r)
183     {
184         mid = (l+r)>>1;
185         if(jud(mid)) ans = mid,r = mid-1;
186         else l = mid+1;
187     }
188     printf("%lld\\n",ans);
189     return 0;
190 }

 

 

以上是关于洛谷 P1084 疫情控制 题解的主要内容,如果未能解决你的问题,请参考以下文章

NOIP2012 洛谷P1084 疫情控制

洛谷 P1084 疫情控制 二分+数据结构

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

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

洛谷 P1084 [NOIP2012 提高组] 疫情控制(二分,倍增,贪心)

P1084 疫情控制