信號放大器【貪心】
【問題描述】
樹型網絡是最節省材料的網絡。所謂樹型網絡,是指一個無環的連通網絡,網絡中任意兩個結點間有且僅有一條通信道路。
網絡中有一個結點是服務器,負責將信號直接或間接地發送到各終端機。如圖6-4,server結點發出一個信號給結點a和c,a再轉發給b。如此,整個網絡都收到這個信號了。
server a b ●-------------○----------○ │ │ ○
但是,實際操作中,信號從一個結點發到另一個結點,會出現信號強度的衰減。衰減量一般由線路長度決定。
server 3 a 2 b ●-------------○----------○ │ │1 ○
如上圖,邊上所標的數字為邊的衰減量。假設從server出發一個強度為4個單位的信號,發到結點a後強度衰減為4-3=1個單位。結點a再將其轉發給結點b。由於信號強度為1,衰減量為2,因此信號無法發送到b。
一個解決這一問題的方法是,安裝信號放大器。信號放大器的作用是將強度大於零的信號還原成初始強度(從服務器出發時的強度)。
上圖中,若在結點a處安裝一個信號放大器,則強度為4的信號發到a處,即被放大至4。這樣,信號就可以被發送的網絡中的任意一個節點了。為了簡化問題,我們假定每個結點只處理一次信號,當它第二次收到某個信號時,就忽略此信號。
你的任務是根據給出的樹型網絡,計算出最少需要安裝的信號放大器數量。
【輸入】
第一行一個整數n,表示網絡中結點的數量。(n<=100000)
第2~n+1行,每行描述一個節點的連接關系。其中第i+1行,描述的是結點i的連接關系:首先一個整數k,表示與結點i相連的結點的數量。此後2k個數,每兩個描述一個與結點i相連的結點,分別表示結點的編號(編號在1~n之間)和該結點與結點i之間的邊的信號衰減量。結點1表示服務器。
最後一行,一個整數,表示從服務器上出發信號的強度。
【輸出】
一個整數,表示要使信號能夠傳遍整個網絡,需要安裝的最少的信號放大器數量。
如果不論如何安裝信號放大器,都無法使信號傳遍整個網絡,則輸出“No solution.”
【樣例輸入】
4
2 2 3 3 1
2 1 3 4 2
1 1 1
1 2 2
4
【樣例輸出】
1
對於任意一個信號放大器安裝,如果安裝在離根較近的點可以且安裝在離根較遠的點也可以的話,則這個信號放大器安裝在離根較近的點會更優,因為離根較近的點的影響範圍比較大。
依此,我們可以從葉結點開始貪心,記錄每個結點傳遍其子樹所需的信號f[i](在滿足安裝最少信號放大器的條件下),並且記錄所有葉結點所需信號為1。
可以得出遞推式f[i]=max(f[j]+dis[i][j]); j∈i結點的子結點的集合
若有子結點的所需信號加上到當前結點的邊權大於服務器發出的信號則在這個子結點上安裝一個信號放大器(因為當前結點不可能發出大於服務器信號的信號,不存在將子樹裝了一個信號放大器還不滿足條件的情況,因為在處理子樹的時候已經解決了這種情況),並將其所需的信號改為1。
無解的情況只存在於有邊的權大於等於服務器發出的信號。
1 #include<cstdio> 2 #include<algorithm> 3 #define R register 4 #define N 100007 5 6 struct info{ 7 int pre,to,dis; 8 }edge[2*N]; 9 10 int n,size,ans,signal,head[N],f[N],fa[N]; 11 12 void addline(int from,int to,int dis){ 13 edge[++size].pre=head[from];head[from]=size; 14 edge[size].to=to;edge[size].dis=dis; 15 } 16 17 void tsdp(int k){ 18 f[k]=1; 19 for (R int i=head[k];i;i=edge[i].pre) 20 if (fa[k]!=edge[i].to){ 21 fa[edge[i].to]=k; 22 tsdp(edge[i].to); 23 int t=f[edge[i].to]+edge[i].dis; 24 if (t<=signal) f[k]=std::max(f[k],t); 25 else ++ans,f[k]=std::max(f[k],1+edge[i].dis); 26 } 27 } 28 29 int main(){ 30 freopen("booster.in","r",stdin); 31 freopen("booster.out","w",stdout); 32 scanf("%d",&n); 33 for (R int i=1;i<=n;++i){ 34 int k;scanf("%d",&k); 35 for (R int j=1;j<=k;++j){ 36 int to,dis; 37 scanf("%d%d",&to,&dis); 38 addline(i,to,dis); 39 } 40 } 41 scanf("%d",&signal); 42 for (R int i=1;i<=size;++i) 43 if (edge[i].dis>=signal){ 44 printf("No solution."); 45 return 0; 46 } 47 tsdp(1); 48 printf("%d",ans); 49 return 0; 50 }
信號放大器【貪心】