樹形DP 換根DP

2022-05-24 14:09:10 字數 1292 閱讀 2504

某些樹形dp問題中, 我們要求的值是類似 "以當前節點為根節點得到的答案", 卻沒有給出固定的根節點, 若仍然按照常規的樹形dp思路對每個點進行dp, 我們對每乙個節點均進行一次 dfs , 最後的複雜度是 \(o\left(n^2\right)\)

如果我們先假設任意乙個點為根進行 dp, 求出當前樹形結構下以每個點為根的子樹的 dp 結果, 然後再將它的結果與父節點的結果一併處理, 也可以得到以它為根節點的整棵樹的 dp 結果, 而這麼做, 我們只需要進行兩次 dfs, 就可以得到答案, 而這麼做, 最後的複雜度只有 \(o\left(n\right)\) , 明顯優於前者, 我們稱這種做法為換根dp.

首先它說每條邊是有方向的, 但實際為了方便 dp, 我們可以建雙向邊, 然後在邊上記錄當前的邊是不是與它自身的指向相反

對於每個節點, 我們可以考慮先求出以某點為根 ( 假設是 \(1\) ) 的 dp 值.

然後我們對每個點的值更新, 方程為:

\[f\left(son\right) = f\left(father\right) \pm 1

\]當父親兒子的邊為正向時, 答案 \(+1\), 反之 \(-1\).

**為什麼用 "\(=\)" ? **

**:

# include # include # define maxn 2000005

using namespace std;

struct edgee[maxn<<1];

int hd[maxn<<1], cnte;

void adde(int u, int v, int w)

int f[maxn], ans; // ans 記錄每一輪計算得到的最小值

void pre(int now, int fa)

} // 先跑一遍以 i 為根的子樹的答案

void dfs(int now, int fa)

} // 再跑一遍以 i 為根的全樹的答案

int main()

f[n] = 0;

pre(1, 0);

dfs(1, 0);

printf("%d\n", ans);

for(int i = 1; i <= n; i++)

printf("\n");

}return 0;

}

樹形 dp 換根 dp

樹形dp 樹形動歸一般是依賴於dfs的,根據動歸的後效性,父節點的狀態一般都依賴子節點的狀態以某種方式轉移而來 換根的p2015 設f i j 表示i的子樹上保留j條邊最多蘋果數 p2279 狀態表示f x 0 覆蓋到x的爺爺和x整棵子樹 向上2層 最少個數 f x 1 覆蓋到x的父親和x子樹 向上...

樹形dp之換根dp

樹形dp之換根dp 換根dp是樹形dp這一類中我覺得比較難的一類。一般的樹形dp都只需要從子樹往父親推,然而換根dp則需要從父親往子樹推,接下來寫寫我學習換根dp的幾個例題。例題1 computer 題目大意 給你一棵樹,然後問你每乙個點具體其他點最遠的距離是多少。解題 這個題目首先任意找乙個點為根...

E Tree Painting 樹形dp 換根

題意 給定一棵樹,一開始點都是白色的,每次你可以對乙個點染色,獲得的分數就是當前點連線的只含白色的點的連通塊的點個數。輸出最多的分數。2 n 2 1 05 2 n 2 10 5 2 n 2 105分析 每次對乙個點進行操作就將樹分成了m棵子樹,並且我們肯定是先操作父節點,再操作子節點,所以自然就想到...