樹型DP簡單入門

2022-07-23 20:39:14 字數 3491 閱讀 7799

anniversary party 題目鏈結

裡面的關係是乙個樹狀的無環圖,每個節點我們顯然有兩種取法,參加派對,不參加派對,所以狀態轉移方程就出來了

#includeusing namespace std;

const int n = 1e4 + 10;

int head[n], to[n], nex[n], in[n], cnt = 1;

int dp[n][2], n;

void add(int x, int y)

void dfs(int rt, int fa)

}}int main()

int x, y;

while(scanf("%d %d", &x, &y) && (x + y))

add(y, x);

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

if(!in[i])

}return 0;

}

p2996 [usaco10nov]visiting cows g

入門題都懂了,這題想必大佬們肯定能寫。

#includeusing namespace std;

const int n = 1e5 + 10;

int head[n], to[n], nex[n], cnt = 1;

int dp[n][2], n;

void add(int x, int y)

void dfs(int rt, int fa)

}}int main()

dp[n][1] = 1;

dfs(1, 0);

printf("%d\n", max(dp[1][0], dp[1][1]));

return 0;

}

rebuilding roads 題目鏈結

思路不難,dp[i][j]陣列,記錄的時第i個節點加上其子樹上與其相連的節點的數量時j時,需要切斷的路徑顯然有dp[i][1] = 與其直接相連的子樹加上乙個父節點的路徑。

然後狀態轉移方程就有了 \(dp[i][j] = min(dp[i][j], dp[i][k] + dp[i_][j - k] - 2)\),這個減二的操作是因為,這兩個之間相連的邊都在互相的dp陣列中記錄了,所以需要減去2。

接下來就要說乙個細節了,我們在最後的答案中dp[root]中所有的都要減去1,因為在之前我們把其父節點的邊加進去了,但是他是沒有父節點的。這個點,坑人啊,還是太菜了。

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

const int n = 2e2 + 10;

int head[n], to[n], nex[n], in[n], cnt;

int dp[n][n], sz[n], n, m;

void add(int x, int y)

void dfs1(int rt, int fa)

}}void solve(int rt, int fa)

}}int main()

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

if(in[i] == 0)

for(int i = 1; i <= n; i++)//好像可以直接在dfs1中完成,,,,

dp[i][1] = sz[i];

// cout << sz[i] << endl;

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

if(in[i] == 0)

// for(int i = 1; i <= n; i++)//除錯bug_ing

// for(int j = 1; j <= m; j++)

int ans = 0x3f3f3f3f;

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

dp[i][m] < ans ? ans = dp[i][m] : ans = ans;//終於出答案了,寫了一長串我現在看不懂的表示式,,,,

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

}return 0;

}

其實也挺好理解的。

最優連通子集 題目鏈結

這是一道要自己建圖的題,顯然我們不難想到,在dis = 1的兩個點之間建立聯通的邊,接下來的事情就是樹上dp了。

考慮狀態轉移方程,對於每乙個點我們可以將其放入聯通集或者不放入聯通集,同時我們還要保證,每乙個點對都是互相連通的。

我們用dp[i][0]表示這個點不在聯通集上,用dp[i][1]表示這個點在聯通集上。

考慮dp[i][0]如何變化,不難發現他的值一定是其子樹上的最大值,所以 \(dp[i][0] = max(dp[i][0], dp[i_][1], dp[i_][0])\)

接著我們考慮dp[i][1],我們要保證它的連通性,得到 \(dp[i][1] = max(dp[i][1], dp[i_][1] + dp[i][1])\)

然後按照這個思路跑一遍dfs就行了。

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

const int n1 = 1e3 + 10, n2 = 1e6 + 10;

int head[n1], to[n2], nex[n2], cnt;

int dp[n1][2], n;

struct point a[n1];

void add(int x, int y)

void dfs(int rt, int fa)

}}int main()

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

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

if((abs(a[i].x - a[j].x) + abs(a[i].y - a[j].y)) == 1)

dfs(1, 0);

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

// printf("%d %d\n", dp[i][0], dp[i][1]);

printf("%d\n", max(dp[1][0], dp[1][1]));

}return 0;

}

本來應該還有第四道題,沒想到考察了樹上揹包,但是這個東西我還沒學過啊,就先咕咕咕咕咕下了。

樹型DP入門

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

樹型DP 選課

大學裡實行學分。每門課程都有一定的學分,學生只要選修了這門課並考核通過就能獲得相應的學分。學生最後的學分是他選修的各門課的學分的總和。每個學生都要選擇規定數量的課程。其中有些課程可以直接選修,有些課程需要一定的基礎知識,必須在選了其它的一些課程的基礎上才能選修。例如,資料結構 必須在選修了 高階語言...

樹型DP 皇宮看守

太平王世子事件後,陸小鳳成了皇上特聘的御前一品侍衛。皇宮以午門為起點,直到後宮嬪妃們的寢宮,呈一棵樹的形狀 有邊直接相連的宮殿可以互相望見。大內保衛森嚴,三步一崗,五步一哨,每個宮殿都要有人全天候看守,在不同的宮殿安排看守所需的費用不同。可是陸小鳳手上的經費不足,無論如何也沒法在每個宮殿都安置留守侍...