NOIP2012 洛谷P1084 疫情控制

2022-04-08 12:52:33 字數 3082 閱讀 7250

description:

h 國有 n 個城市,這 n 個城市用 n-1 條雙向道路相互連通構成一棵樹,1 號城市是首都,也是樹中的根節點。

h 國的首都爆發了一種危害性極高的傳染病。當局為了控制疫情,不讓疫情擴散到邊境城市(葉子節點所表示的城市),決定動用軍隊在一些城市建立檢查點,使得從首都到邊境城市的每一條路徑上都至少有乙個檢查點,邊境城市也可以建立檢查點。但特別要注意的是,首都是不能建立檢查點的。

現在,在 h 國的一些城市中已經駐紮有軍隊,且乙個城市可以駐紮多個軍隊。一支軍隊可以在有道路連線的城市間移動,並在除首都以外的任意乙個城市建立檢查點,且只能在乙個城市建立檢查點。一支軍隊經過一條道路從乙個城市移動到另乙個城市所需要的時間等於道路的長度(單位:小時)。

請問最少需要多少個小時才能控制疫情。注意:不同的軍隊可以同時移動。

input:

第一行乙個整數 n,表示城市個數。

接下來的 n-1 行,每行 3 個整數,u、v、w,每兩個整數之間用乙個空格隔開,表示從城市 u 到城市 v 有一條長為 w 的道路。資料保證輸入的是一棵樹,且根節點編號為 1。

接下來一行乙個整數 m,表示軍隊個數。

接下來一行 m 個整數,每兩個整數之間用乙個空格隔開,分別表示這 m 個軍隊所駐紮的城市的編號。

output:

共一行,包含乙個整數,表示控制疫情所需要的最少時間。如果無法控制疫情則輸出-1。

思路:首先二分答案,然後對於每支軍隊,到根節點的子節點的距離小於mid的全都到根節點的子節點集中,其他軍隊都盡量往上走,能走到哪就是哪。然後將根節點的子節點上的軍隊剩餘時間排序,剩餘時間最小且無法做到去一趟根節點再回來的軍隊駐守在原來的子節點上,其他軍隊都到根節點上,然後排序,並將所有沒有軍隊的子節點排序,貪心掃瞄一遍即可

#include#include

#include

#include

#include

#define ll long long

using

namespace

std;

const

int n = 50050

;typedef pair

p;inthead[n], now;

struct

edgesedge[n

<<1

];void add(int u,int v,int w); head[u] =now;}

//dep儲存深度,pre儲存每個點父節點,e_pre儲存每個點的上一條邊 dict儲存每個點所對應的根節點的子節點

//pos儲存軍隊初始位置 f儲存每個根節點的子節點上的病毒能否到達葉子

intn, m, pre[n], pos[n], dict[n], e_pre[n];

ll l, r, tot, dep[n];

bool stop[n], f[n]; //

stop指那些無法到達根節點的子節點的軍隊停留的位置

vector id[n]; //

id儲存每個根節點的子節點下的軍隊

vectorvec[n]; //

該錶儲存的是每個根節點的子節點上駐紮的軍隊以及剩餘時間

vector a, b; //

該錶儲存的是軍隊的剩餘時間和每個軍隊到根節點後再到各個子節點的距離

int dfs1(int x,int root)

for(int i = head[x]; i; i =edge[i].next)

}bool dfs2(int

x)

if(!flag) return0;

return1;

}void

init()

void work(int x,int

lim)

stop[x] = 1;}

bool cmp(p x, p y)

bool che(int

lim)

vec[dict[i]].push_back(p(i, lim - (dep[p] -dep[dict[i]])));

}for(int i = head[1]; i; i = edge[i].next)

for(int i = head[1]; i; i =edge[i].next)

sort(vec[v].begin(), vec[v].end(), cmp);

//將每個點排序之後貪心地將剩餘時間最短的軍隊駐紮在原地

int tmp = vec[v][0].second; //

取出剩餘時間最少的點

if(tmp - 2 * edge[i].w < 0 && !f[v]) flag = 1; //

該節點已經被管制

else a.push_back(tmp -edge[i].w);

for(int j = 1; j < vec[v].size(); j++)

if(!flag && !f[v])

b.push_back(edge[i].w);

}sort(a.begin(), a.end());

//貪心掃瞄 剩餘時間最少的軍隊去最近的子節點

sort(b.begin(), b.end());

int s = 0

;

for(int i = 0; i < a.size(); i++)

if(s == b.size()) return1;

else

return0;

}int

main()

scanf("%d

",&m);

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

scanf("%d

",&pos[i]), id[pos[i]].push_back(i);

for(int i = head[1]; i; i =edge[i].next)

r =tot;

ll ans =1e15;

while(l <=r)

if(ans == 1e15) puts("-1"

);

else printf("

%lld\n

",ans);

return0;

}

view code

洛谷P1084 (疫情控制)

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

洛谷P1084 疫情控制

題目 細節比較多的二分 跟lca倍增差不多的思想 首先有這樣乙個貪心思路,深度越低的檢查點越好,而最長時間和深度具有單調性,即給定時間越長,每個軍隊能向更淺的地方放置檢查點。因此可以考慮二分時間,然後判斷軍隊是否可以放置在控制疫情的地方。include define n 1001001 using ...

洛谷P1084 運輸計畫

題目 題目要求使一條邊邊權為0時,m條路徑的長度最大值的最小值。考慮二分此長度最大值 首先需要用lca求出樹上兩點間的路徑長度。然後取所有比mid大的路徑的交集,判斷有哪些邊在這些路徑上都有出現,然後這些邊裡面取最大值當做蟲洞,如果還是不行說明此mid不行。判斷邊可以用把邊化為點,然後樹上差分判斷每...