疫情控制(二分 貪心 倍增)

2022-03-14 12:18:16 字數 3216 閱讀 2792

noip 2012 提高組 第二天 第三題

題目描述:

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。

思路:

二分答案+倍增檢驗+貪心思路

首先明白目的是什麼:求把首都(1節點)圍住的最少時間,注意:不一定非要到根節點的兒子節點才可以,把這一條路封住就可以了。

所以二分乙個時間後,是這個點盡量往上走(盡量接近首都),這裡會出現兩種情況:1、二分的時間不夠到達首都,在中途停了下來,停下來的點設為訪問過。2、二分的時間足夠到達首都,開個結構體b記錄一下。

對於第一種情況,因為這個點沒有到首都,所以進行標記上傳。至於什麼作用,接著往下看。

對於第二種情況,這個點到達了首都,它就有兩種選擇,一是回到它來的路徑上那個最靠近首都的點,二是跨過根節點去覆蓋其他的點。

開乙個c結構體,僅僅掃瞄首都節點的兒子!記錄沒有軍隊的兒子,c[i].from表示首都的兒子,c[i].w表示首都到這個兒子的時間。

說到這裡,就很容易理解標記上傳了,因為第一種情況中說到了,這個點沒有到達首都,它可能是首都的兒子,也可能是首都的孫子,更可能是距離首都很遠的乙個點,但是它算在的這條路徑已經是被這個點覆蓋了(疫情不會從這裡擴散出去!),然而結構體c僅僅掃瞄了首都的兒子節點,所以在這條路徑上的首都的兒子可能沒有覆蓋,所以寫乙個函式color把這個點的情況傳給它所在路徑上的首都的兒子,也就是所謂的標記上傳。

現在,就可以掃瞄首都兒子,在結構體c中進行記錄了。

記錄完成之後,繼續用到貪心思路,b、c結構體排序。

具體情況在**中會有詳解!

最後輸出答案

完成

#include

#include

#include

using

namespace

std;

const

int maxn=50010;

int l,r,mid,ans=-1;

int n,m,tot,head[maxn];

int f[maxn][20],dis[maxn][20],deep[maxn];

int a[maxn],vis[maxn];

struct edge

e[maxn<<1];

struct node

b[maxn<<1],c[maxn<<1];

void add_edge(int u,int v,int w)

void build(int u)

}void init()

}void color(int x)//標記上傳,因為下面結構體c是掃瞄的

if(p&&q&&x!=1)

vis[x]=1;

}bool cmp(node x,node y)

if(y!=1) vis[y]=1;//到不了首都

else

//到了首都,用b記錄

}color(1);//標記上傳

for(int i=head[1];i;i=e[i].next)//c記錄哪個首都兒子沒有軍隊

if(!vis[e[i].to])

sort(b+1,b+cnt+1,cmp);//把到達首都點的剩餘時間從大到小排序

sort(c+1,c+top+1,cmp);//把沒有軍隊的首都兒子從小到大排序

int j=1;c[top+1].w=0x3f3f3f3f;

for(int i=1;i<=cnt;i++)

if(j>top)

return

1; return0;}

int main()

cin>>m;

for(int i=1;i<=m;i++)

cin>>a[i];

deep[1]=1;

f[1][0]=1;

build(1);//lca見樹

init();//lca預處理

while(l<=r)//二分答案

else l=mid+1;

}cout

0;}

P1084 疫情控制(二分答案,倍增,貪心)

p1084 疫情控制 給定一棵樹,一些點 不包括樹根 上有軍隊,每條邊有乙個邊權 移動時間 各個軍隊可以同時移動,求最小的移動時間,使得每條通往任意葉子結點的路徑上至少都有一支軍隊.二分答案 通過觀察題意可知,答案具有單調性 如果p pp小時時能控制所有的邊境城市,那麼q q p q q p q q...

NOIP2012 疫情控制 貪心 二分 倍增

一道很全 du 面 liu 的題 題目大意 給定一棵樹,用最少的時間封住這棵樹。題解 首先可以很容易發現乙個條件 軍隊在走的時候都要盡量往上走,但不到根節點。因為越靠近根節點的點,控制的葉子節點越多。不過暴力是肯定會超時的,用倍增優化。題目求的是最長移動時間軍隊的最短時間,想到二分答案。但是還有這樣...

洛谷 1084 疫情控制 倍增 二分

h國有 n個城市,這 n 個城市用n 1條雙向道路相互連通構成一棵樹,1號城市是首都,也是樹中的根節點。h國的首都爆發了一種危害性極高的傳染病。當局為了控制疫情,不讓疫情擴散到邊境城市 葉子節點所表示的城市 決定動用軍隊在一些城市建立檢查點,使得從首都到邊境城市的每一條路徑上都至少有乙個檢查點,邊境...