一棵n個點的有根樹,1號點為根,相鄰的兩個節點之間的距離為1。樹上每個節點i對應乙個值k[i]。每個點都有乙個顏色,初始的時候所有點都是白色的。
你需要通過一系列操作使得最終每個點變成黑色。每次操作需要選擇乙個節點i,i必須是白色的,然後i到根的鏈上(包括節點i與根)所有與節點i距離小於k[i]的點都會變黑,已經是黑的點保持為黑。問最少使用幾次操作能把整棵樹變黑。
第一行乙個整數n (1 ≤ n ≤ 10^5)接下來n-1行,每行乙個整數,依次為2號點到n號點父親的編號。
最後一行n個整數為k[i] (1 ≤ k[i] ≤ 10^5)
樣例解釋:
對節點3操作,導致節點2與節點3變黑
對節點4操作,導致節點4變黑
對節點1操作,導致節點1變黑
乙個數表示最少操作次數示例1
41211 2 2 1
3思路:我們發現其實不管採用怎樣的染色策略,樹的所有葉子節點是一定要操作的,因此我們很容易想到的乙個貪心策略是自底向上進行模擬,對於當前操作的點,我們能夠很容易知道這個點操作後能延伸到**,當我們向上回溯的時候直到葉子節點無法延伸到該點時我們對當前點進行操作,但是很容易證明這個貪心思想是錯誤的!
這道題其實是一種很簡單的動態規劃思想,只是為了增大難度放在了樹上而已,如果我們簡單的通過最遠的操作點進行計數並不能在任意情況下達到最優解,很簡單的反例就是某個非葉子節點的k值非常大,若當前點已經被其某個子節點覆蓋到,我們是有可能通過操作這個點從而得到更優的解的,因此我們需要考慮動態規劃,通過維護來自子節點往上最遠的覆蓋距離,當這個覆蓋距離為0時,說明這個點無法覆蓋,我們需要新增乙個節點,我們選取的點應該是越過這個點可以往上走最遠的節點塗黑。
#include#include#includeusing namespace std;
#define maxn 100005
int k[maxn],n,dp[maxn],ans;
vectorq[maxn];
void dfs(int u,int f)
if(!dp[u])
}int main(void)
for(int i=1;i<=n;i++)
scanf("%d",&k[i]);
dfs(1,0);
printf("%d\n",ans);
return 0;
}
黑白樹(牛客網 樹形dp)
題目描述 一棵n個點的有根樹,1號點為根,相鄰的兩個節點之間的距離為1。樹上每個節點i對應乙個值k i 每個點都有乙個顏色,初始的時候所有點都是白色的。你需要通過一系列操作使得最終每個點變成黑色。每次操作需要選擇乙個節點i,i必須是白色的,然後i到根的鏈上 包括節點i與根 所有與節點i距離小於k i...
Nowcoder 黑白樹 樹形dp
一棵n個點的有根樹,1號點為根,相鄰的兩個節點之間的距離為1。樹上每個節點i對應乙個值k i 每個點都有乙個顏色,初始的時候所有點都是白色的。你需要通過一系列操作使得最終每個點變成黑色。每次操作需要選擇乙個節點i,i必須是白色的,然後i到根的鏈上 包括節點i與根 所有與節點i距離小於k i 的點都會...
牛客訓練,殺樹,樹形dp
一道樹形dp題,我剛開始想的是dp i j dp i j dp i j 表示i為根結點最長鏈的長度為j的最小代價,轉移的時候很複雜,最後還是沒寫出來 也有可能是寫炸了,但是這個狀態應該也是可以的 比賽結束後看到題解是用dp i j dp i j dp i j 表示i為根結點最長鏈的長度小於等於j的最...