給定一棵帶點權樹,選出一個最佳的根節點,使得根節點的點權不變,它的兒子點權加\(1\),其他點點權加\(2\),並使最大點權最小,輸出這個最小的最大點權。(我愛死洛谷上的這個翻譯了!本來老長的題設精簡成了這麼簡單易懂的樣子)c++
一眼看去是否是樹形\(DP\)?太複雜了不想寫啊,能寫別的是不可能寫樹形\(DP\)的,這輩子都不可能寫樹形\(DP\)的。這麼簡單的題意,確定有別的寫法吧?
確實有!
總感受這個題沒有代碼不太好說,直接看下面代碼的註釋吧……數組
#include<bits/stdc++.h> using namespace std; #define v e[j].to//注意這裏,下面的v都是e[j].to const int maxn=300000+3; int a[maxn]; struct edge{ int next,to; }e[2*maxn]; int n,ans,fin,tot,head[maxn];//fin表明最終答案 map<int,int> m;//鍵爲點權,值爲編號 //由於權值有負數不能用數組 void Add(int a,int b){ e[tot].to=b; e[tot].next=head[a]; head[a]=tot; tot++; } int main(){ ans=-1000000000;//找最大值 tot=1; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); ans=max(ans,a[i]); m[a[i]]++;//記錄權值出現了幾回 } for(int i=1;i<=n-1;i++){ int x,y; scanf("%d%d",&x,&y); Add(x,y); Add(y,x); } fin=ans+2;//若是沒有更小答案fin就是ans+2 for(int i=1;i<=n;i++){ bool judge=0; for(int j=head[i];j;j=e[j].next){ m[a[v]]--;//記錄兒子的權值 if(a[v]==ans) judge=1;//記錄兒子裏是否有最大值 } if(!m[ans]) fin=ans+1;//這說明全部的最大值都在兒子裏,因此fin=ans+1 if(m[ans]==1&&a[i]==ans){//這說明最大值在根節點 if(judge) fin=ans+1;//最大值在根節點的狀況下兒子裏還有最大值,確定兒子由於加了1較大 else if(m[ans-1]) fin=ans-1+2;//兒子裏面沒有最大值了可是兒子以外有權值爲ans-1的節點權值+2 //因此這裏爲了看的明白沒有直接寫ans+1 else{ fin=ans;//只有根節點是最大值了,沒有別的能夠超過 break;//記得break!!!在這裏栽了兩次 //爲何要break?這已是最佳答案了,以後再計算會再變回更大的值 } } for(int j=head[i];j;j=e[j].next) m[a[v]]++; } printf("%d",fin); }
幸甚至哉,歌以詠志。spa