洛谷 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。
输入输出样例
4 1 2 1 1 3 2 3 4 3 2 2 2
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 疫情控制 题解的主要内容,如果未能解决你的问题,请参考以下文章
洛谷P1084 [NOIP2012提高组Day2T3]疫情控制