NOIP2012提高組 疫情控制

2021-08-28 11:09:41 字數 2906 閱讀 2947

noip2012 提高組 day2 試題。

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解析:

挺有意思的一道題。

然而到現在我都不知道暴力怎麼打。。。

以下解析借鑑於這位大佬:[noip2012提高組]疫情控制

首先,這道題是要求最少的時間,可以二分答案

然後是乙個貪心的思路:讓每支軍隊盡在二分的時間內盡可能多的控制城市,所以盡量向上爬

因為軍隊越往上,能封住的葉子節點就越多(至少不會減少),那我們在能往上的情況下,盡可能往上。

一支軍隊如果不能到根節點,就讓其在能爬到的最高點停下,並封鎖這個節點。

如果能則記錄下它剩下的時間和它經過的《根節點的兒子》的編號(即它從哪個兒子過來的)。

然後我們dfs出已經被封鎖的節點,如果乙個節點的所有兒子都被封鎖,則該節點也算被封鎖。

之後我們把所有《沒被封鎖的,根節點的兒子》的編號和到根節點的距離記錄下來。

再然後,我們的任務就是把剛剛記錄的那些節點,用剩下的能到達根節點的軍隊去覆蓋。於是又是貪心,把節點按照到根節點的距離公升序排序,把軍隊按照剩餘時間公升序排序,然後對於乙個節點,用剩餘時間最少的,且比這個節點到根節點的距離大(因為要走過去)的軍隊覆蓋。(就是盡量用剩餘時間少的軍隊去覆蓋)

注意:如果乙個軍隊「經過的《根節點的兒子》」沒有被覆蓋,則優先覆蓋。

最後如果能成功覆蓋所有根節點的兒子,則說明答案可行,否則不可行。

對於讓軍隊向上爬的過程,我們可以用倍增的方法進行優化,所以要先預處理。

①預處理倍增。

②二分答案。

對於每個二分的答案:

①讓每個軍隊盡可能向上爬。對於不能到根節點的,讓其在能到達的最高節點停下,否則記錄下來。對記錄資料排序。

②找出所有未被封鎖的《根節點的兒子》記錄。對記錄資料排序。

③用剩餘軍隊覆蓋所有未被封鎖的根節點的兒子。判斷答案是否可行。

**:

#include using namespace std;

const int max=50005;

int n,m,size,l,r,mid,tot1,tot2;

int first[max],num[max],f[max][18],d[max][18],p[max],vis[max];

struct bian;

bian edge[max<<1];

struct shu;

shu a[max],b[max];

inline int get_int()

inline void build(int x,int y,int z)

inline void dfs(int point,int fa)

}inline void pre()

inline void search(int point,int fa)

if(!tag) vis[point]=0; //葉子節點需特判

}inline bool comp(const shu &a,const shu &b)

search(1,0);

if(vis[1]) return 1;

for(int u=first[1];u;u=edge[u].next)

if(!vis[edge[u].to]) b[++tot2].len=edge[u].len,b[tot2].id=edge[u].to;

sort(a+1,a+tot1+1,comp),sort(b+1,b+tot2+1,comp);

if(tot1=b[tag].len) vis[b[tag].id]=1;

while(tag<=tot2&&vis[b[tag].id]) tag++;

if(tag>tot2) return 1;

}return tag>tot2;

}int main()

if(tag) cout

return 0;

}

NOIP2012提高組 疫情控制

題目 洛谷p1084 codevs1218 vijos p1783。題目大意 有一棵n個節點的,根為1的帶權樹和m支軍隊。每支軍隊可以在乙個點上停下,那麼從1開始就不能經過這個點了。現在有m支軍隊已經在某些點上,移動一支軍隊到乙個相鄰的點所花時間等於該條邊的邊權。軍隊可同時移動。問至少多少時間才可以...

NOIP2012 疫情控制

詳細的注釋已經寫到了 裡面。以後這種碼量多的最好都寫成函式再呼叫,確定好每個函式的作用。然後變數名最好也是有實際意義的qwq include include include include include define maxn 500010 using namespace std int n,m,...

NOIP 2012 疫情控制

題目鏈結 演算法 細心觀察發現 此題的答案具有單調性,也就是說,如果p小時能控制疫情,那麼q小時也能控制疫情 q p 因此我們可以二分答案,這是此題的突破口 問題就轉化為了檢驗 mid小時是否可以控制住疫情 我們發現,既然要求所有葉子節點得到管轄,那麼,軍隊所在的節點深度越淺,所能管轄的節點數就越多...