樹形dp
樹形動歸一般是依賴於dfs的,根據動歸的後效性,父節點的狀態一般都依賴子節點的狀態以某種方式轉移而來
換根的p2015
\[設f[i][j]表示i的子樹上保留j條邊最多蘋果數\\
\]p2279
\[狀態表示f[x][0]:覆蓋到x的爺爺和x整棵子樹(向上2層),最少個數\\
f[x][1]:覆蓋到x的父親和x子樹(向上一層)\\
f[x][2]:覆蓋到x整顆子樹(向上0層)\\
f[x][3]:覆蓋x的兒子及其子樹(向上-1層)\\
f[x][4]:覆蓋所有x的孫子及其子樹(向上-2層)\\
顯然f[x][i]一定包含f[x][i+1],y.z是x的兒子\\
f[x][0]=1+\sum f[y][4](因為i可以覆蓋到向上2層,所以它自己必須是消防站~顯然)\\
x的兒子中有乙個一定覆蓋的爺爺,同時覆蓋到兄弟(因為y一定是選了),其他的兒子只需要覆蓋的自己的兒子即可\\f[x][1]=min(f[y][0]+\sum f[z][3](y!=z))\\
f[x][2]=min(f[y][1]+\sum[z][2])有乙個兒子覆蓋到父親,但無法覆蓋到y的兄弟,所以其他兒子要覆蓋到自己\\
f[x][3]=\sum f[y][2]讓每個兒子覆蓋到自己即可\\
f[x][4]=\sum f[y][3]讓每個兒子覆蓋到自己的兒子\\
\]p1122 最大子樹和
\[設f[i][0]為被當前這個點保安控制的點\\
顯然f[i][0]=\sum min(f[son[i]][0],f[son[i]][1],f[son[i][2])+val[i]\\
f[i][1]為被當前這個點的兒子控制的點\\
顯然f[i][1]=\sum min(f[son[i][0],f[son[i]][1])如果選擇的全部都是f[son[i]][1],\\要再加上min(f[son[i]][0]-f[son[i]][1])\\
f[i][2]為被當前這個點的fa控制的點\\
這個有點麻煩f[i][2]=\sum min(f[son[i]][0],f[son[i]][1])我們不妨這樣理解,對於i節點我們讓它\\的父親節點fa覆蓋它,那麼根據我們的狀態設計,此時必須要滿足以i的兒子son[i]為根的子樹\\之中所有點已經被覆蓋那麼這時就轉化為乙個子問題,要讓y子樹滿足條件,只有兩種決策:要麼son[i]\\被son[i]的兒子覆蓋,要麼被son[i]自己覆蓋(即選擇son[i]節點)\\,只需要在son[i]的這兩種狀態取min累加就可以了
\]對於\(f[i][1]\)的轉移,luogu大佬有詳細解釋:(這位大佬)\(\_\_\_new2zy\_\_\_\)
我們可以這樣理解,此時既然要保證x點是被自己的兒子覆蓋的,那麼如果此時y子樹已經滿足了全部被覆蓋,但是y此時被覆蓋的狀態卻是通過y節點自己的兒子達到的,那麼x就沒有被兒子y覆蓋到,那麼我們不妨推廣一下,如果x所有的兒子y所做的決策都不是通過選擇y點來滿足條件,那麼我們就必須要選擇x的乙個子節點y,其中y滿足\(f[y][0]-f[y][1]\)最小,並把這個最小的差值累加到\(f[x][1]\)中去,這樣才能使得x點被自己的兒子覆蓋**,狀態\(f[x][1]\)也才能合理地得到轉移
就是這樣1代表選了該點,0沒選,假設問號為根節點,0為枝條,1為葉子,這樣顯然不行,所以取最小花費的點,加入到花費,明白了吧
0 0 0 0
1 1 1 1
//**哥哥:
#include#define maxn 1520
#define int long long
using namespace std;
inline int min(int a,int b)
while(c>='0'&&c<='9')
return f*p;}
struct edgee[maxn<<1];
int n,tot=0,head[maxn<<1],val[maxn];
int f[maxn][4];
inline void add(int x,int y)//加邊
inline int treedp(int u,int fa)
} treedp(1,0);
printf("%d",min(f[1][0],f[1][1]));
}
換根dp一般分為三個步驟
1、先指定乙個根節點
2、一次dfs統計子樹內的節點對當前節點的貢獻
3、一次dfs統計父親節點對當前節點的貢獻並合併統計最終答案
二次掃瞄與換根法:
\(f[i]表示以u為根的樹的深度和,size[i]表示以i為根子樹的結點個數\)
\(f[v]=f[u]-size[x]+n-size[x]=f[u]+n-2*size[x]\)
本來是以u為根的樹,變成以兒子v為根的樹,
那麼v的所有結點的深度都會減1,深度和就會減少size[v],
同樣地,所有不在v的子樹上的結點的深度都會+1,深度和就會加上n - size[v],
樹形DP 換根DP
某些樹形dp問題中,我們要求的值是類似 以當前節點為根節點得到的答案 卻沒有給出固定的根節點,若仍然按照常規的樹形dp思路對每個點進行dp,我們對每乙個節點均進行一次 dfs 最後的複雜度是 o left n 2 right 如果我們先假設任意乙個點為根進行 dp,求出當前樹形結構下以每個點為根的子...
樹形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棵子樹,並且我們肯定是先操作父節點,再操作子節點,所以自然就想到...