noip 2012 提高組Day2T3 疫情控制

2022-04-30 13:00:11 字數 2777 閱讀 6828

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保證軍隊不會駐紮在首都。 

對於20%的資料,2≤ n≤ 10; 

對於40%的資料,2 ≤n≤50,0

a了這道題之後無意中發現可以把自己的**hack掉(放出的**是已經修改完的,啊當然有可能還會被hack掉)

以下是資料:2 1 2 5 1 2,應輸出0。

這組資料也可以hack掉網上的很多題解……然而vijos和codevs都沒卡。

方法是二分+貪心+拓撲排序/倍增,這裡用的是拓撲排序。

貪心可得,每個軍隊盡量要往上走。二分出mid之後,

走不到根節點的軍隊就走到他們所能到達的最靠近根節點的節點,能走到根節點的軍隊則扔進乙個佇列裡,再將根節點尚未被控制的子節點扔進另乙個佇列,

每個子節點需要一支軍隊控制。貪心可得,

將軍隊走到根節點後的剩餘時間從小到大sort一發,再按根節點到子節點所需時間將子節點sort一發,一一匹配即可。

詳見**。

1 #include2 #include3 #include4 #include5

#define ll long long

6using

namespace

std;

7const

int n=50010;8

intn,m,cnt,u,v,w,cnt1,cnt2,first[n];

9int

army[n],q[n],fa[n],anc[n],t1[n],t2[n];

10//

anc[i]代表控制節點i的根節點的子節點的編號

11bool

notl[n],arr[n],mark[n];

12//

arr[i]代表節點i的子樹所包括的葉子結點是否全部被控制

13ll l,r,tot,dis[n],cost[n],t[n];

14//

t[i]代表軍隊往上走到達節點i剩餘時間最大值

15struct edgee[n*2

];16

intread()

1720

while(c>='

0'&&c<='9')

21return x*f;22}

23void ins(int u,int v,int

w)24

28bool cmp1(int a,int b)

29bool cmp2(int a,int b)

30void

bfs()

3148}49

}50bool

check(ll mid)

5163 cnt1=cnt2=0;64

for(int i=first[1];i;i=e[i].next)

65if(!arr[e[i].to])t1[++cnt1]=e[i].to;//

將根節點尚未被控制的子節點扔進佇列

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

67if(dis[army[i]]<=mid)t2[++cnt2]=i;//

將所有可以使用的軍隊扔進佇列

68if(cnt1==0)return

true;//

若已經全部控制,則直接返回true

69 sort(t1+1,t1+cnt1+1

,cmp1);

70 sort(t2+1,t2+cnt2+1

,cmp2);

71for(int i=1,j=1;i<=cnt2;i++)

7278

return

false;79

}80intmain()

8188 tot=r;

89 m=read();

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

91 army[i]=read(),mark[army[i]]=true;92

bfs();

93while(l<=r)

9499

if(l==tot+1)printf("-1"

);100

else printf("

%lld

",l);

101return0;

102 }

view code

NOIP2012提高組Day1T2 國王遊戲

國王遊戲 描述恰逢 h 國國慶,國王邀請 n 位大臣來玩乙個有獎遊戲。首先,他讓每個大臣在左 右手上面分別寫下乙個整數,國王自己也在左 右手上各寫乙個整數。然後,讓這 n 位大臣排成一排,國王站在隊伍的最前面。排好隊後,所有的大臣都會獲得國王獎賞的若干金幣,每位大臣獲得的金幣數分別是 排在該大臣前面...

NOIP2012 提高組 day1 國王遊戲

題解這道題是一道貪心題,大家只需要找到貪心策略是左手與右手的乘積,然後從小到大sort一下就ok了 不過大家有一點需要小小注意一下,需要打乙個高精度,要不然就只有60了 include define maxn 10005 using namespace std int a 10005 n,len,x...

NOIP2012 提高組 day1 國王遊戲

由公式推導出 當大臣按照 a b由小到大排列時,會使得答案取到最小,算出每個人的金幣數比較即可 要用高精度乘法和除法,否則只有60分。include h using namespace std typedef long long ll const int n 10050,m 4005 struct ...