樹形DP入門

2022-02-02 22:38:25 字數 3175 閱讀 9717

給定一顆有n個節點的樹(一般是無根樹,就有n-1條無向邊),可以任選乙個節點作為根節點

一般以節點從深到淺(子樹從小到大)的順序作為dp階段順序

dp的狀態表示中,第一維通常是節點編號(節點編號代表了以該節點為根的子樹)

對於每個節點x,先遞迴在它的每個子節點上進行dp,回溯時,從子節點向x進行狀態轉移

n個員工,編號為1~n

他們之間有從屬關係,也就是說他們的關係就像一棵以校長為根的樹,父結點就是子結點的直屬上司。現在有個宴會,宴會每邀請來乙個員工 i 都會增加一定的快樂指數 ri,但如果某個員工的直屬上司來了,那麼這個員工就不會來。計算邀請哪些員工可以使快樂指數最大,輸出最大的快樂指數

dp [x] [0]表示在 x 為根的子樹中邀請部分員工,並且x 不參加時,快樂指數總和的最大值,此時 x 子節點(直接下屬)可以參加也可以不參加 (s表示x子節點)

dp [x] [1]表示在 x 為根的子樹中邀請部分員工,並且x 參加時,快樂指數總和的最大值,此時 x 子節點(直接下屬)都不能參加,h[x] 表示當前節點(x)的快樂指數 (s表示x子節點)

這個題給的是有根樹,就可以從根節點開始,dp目標就是 max(f[root,0] , f[root,1]) 時間複雜度on

#include #include #include #include #include using namespace std;

vectorson[10010];

int dp[10010][2];//0不參加,1參加

int v[10010];//記錄有沒有父節點

int h[10010];//記錄快樂指數

int n;

void dfs(int x)

}int main()

int root;

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

if(!v[i])

dfs(root);

cout << max(dp[root][0],dp[root][1]) << endl;

return 0;

}

有n個點,在某些點上放置哨兵,每個哨兵可以監控和它有邊相連的點,問監視所有的點需要的最少的哨兵數

也就是說一顆n個結點的樹,要求選出其中的一些頂點,使得對於樹中的每條邊(u, v),u和v至少有乙個被選中,要求給出選中頂點數最少的方案

dp [x] [0]表示在不選擇節點 x 的情況下,以 x 為根節點的子樹,最少需要選擇的節點數

​ 當i為葉子節點時

​ 當i不為葉子節點時 (s表示x子節點)

dp [x] [1]表示在選擇節點 x 的情況下,以 x 為根節點的子樹,最少需要選擇的節點數

​ 當i為葉子節點時

​ 當i不為葉子節點時 (s表示x子節點)

#include #include #include #include #define maxn 1508

using namespace std;

int dp[maxn][2];

int soncnt[maxn];

int parent[maxn];

int n;

void dfs(int x)

for (i=0; i < n; i++)

}dp[x][1] = d1 + 1;

dp[x][0] = d0;

}int main()

while (m--)

}dfs(root);

cout << min(dp[root][0], dp[root][1]) << endl;

}return 0;

}

給一顆n個結點的樹,節點編號為1~n

問:刪除哪些結點後,剩餘各個子樹的大小均小於原總結點數的一半

拆除乙個節點後,剩餘部分為其若干兒子的子樹以及該節點上層所連其餘部分(n-size[i]),只要這些連線塊大小都不超過n/2,該節點就滿足條件。因而我們可以先求出每個節點所管轄的那棵樹的大小,自下而上地為每個節點求出其子樹規模(該點規模=其兒子的規模和+1)。

在建樹的時候可以直接用連線表(vector)儲存無向邊,這時由於無法區分與每個點相連的是其父節點還是子節點,會引發問題:在dfs的時候把父節點誤認作兒子節點,解決方法就是在遞迴的時候傳入父節點編號,然後在遞迴,計算規模,比較大小的時候避開它就可以了

#include#include#include#include#includeusing namespace std;

int n;

int root;

vectorg[10000+400];

vectorans;

int sz[10000+400];

void dfs(int par,int u)

int piece=0;

for(int i=0;i

if(par!=g[u][i])

piece=max(piece,n-sz[u]);

if(piece<=n/2)

ans.push_back(u);}

int main()

for(int i = head[u]; ~i; i = nxt[i])

}}int lca(int u, int v)

if(u == v) return u;

for(int i = 19; i >= 0; --i)

}return fa[u][0];

}

樹形DP入門

hdu1011 一棵樹,有n個結點,每個結點有v個bug,有w的brain。我從1號結點開始走,帶著m個戰士。1個戰士可以消滅20個bugs,如果我把某個結點的所有bug都消滅了我就能得到那個結點的brain。如果想攻擊當前結點,那麼必須先攻擊了它的父結點 1號點除外 其中當你攻占了當前結點,你可以...

樹形dp 入門

以前看過點樹形dp,不過全忘了。今天做了一道入門級的簡單題,回憶了一下。所謂樹形dp就是在一棵樹上進行狀態轉移。有時候他的狀態轉移方程比普通dp還簡單,只不過建圖比較麻煩,順便複習了一下鄰接表的用法,真是好久不練就都忘了。下面是一道最基礎的題,要求父節點和兒子節點不能同時選,求最大權值,很明顯狀態轉...

樹形DP入門

先入門一下 題意 某公司要舉辦一次晚會,但是為了使得晚會的氣氛更加活躍,每個參加晚會的人都不希望在晚會中見到他的直接上司,現在已知每個人的活躍指數和上司關係 當然不可能存在環 求邀請哪些人 多少人 來能使得晚會的總活躍指數最大。思路 任何乙個點的取捨可以看作一種決策,那麼狀態就是在某個點取的時候或者...