1575 例 1 二叉蘋果樹 樹形DP

2021-10-24 15:36:20 字數 2715 閱讀 3201

1575:【例 1】二叉蘋果樹

問題描述

有一棵二叉蘋果樹,如果數字有分叉,一定是分兩叉,即沒有只有乙個兒子的節點。這棵樹共 n 個節點,標號 1 至 n,樹根編號一定為 1。

我們用一根樹枝兩端連線的節點編號描述一根樹枝的位置。一棵有四根樹枝的蘋果樹,因為樹枝太多了,需要剪枝。但是一些樹枝上長有蘋果,給定需要保留的樹枝數量,求最多能留住多少蘋果。

這一題讓我們 從一棵樹中刪除一些邊,是剩餘的邊數為 m,其實就是從原來的那棵樹上,刪去一子樹,使剩下的 m 條邊的權值之和最大,

思路大致是:先 dfs 到葉子節點,之後從下往上的回溯過程中,對於回溯過程中遇到的節點 u,解決了以 u 為子樹的問題的最優解之後,繼續回溯,解決字數問題的最優解,,,,這樣當我 乙個乙個點解決的每一子樹的最優解問題之後,回溯到 根節點,就可以解決 整棵樹的 最優解問題了,

對於每一顆子樹的最優解,假設這顆子樹以 u 為根,假設 u 有 v1、v2…vx 個節點,我們可把求解子樹的最優解的問題轉化為揹包問題的求解最優解的問題,我們可以把這些子節點,當成乙個揹包問題的中的物品,而 m 自然是揹包的空間,當我們給每個物品分配的 空間(邊數)不同的時候,這件物品的價值也會隨著改變(這應該可以叫做:泛化物品 吧),對於這種物品價值隨著分配空間改變的物品的解決方案就是,我們在揹包的問題的兩層 for 迴圈的基礎上,在加上一層 for 迴圈來列舉給當前物品 v 分配的空間,

那麼我們就按照揹包的思想來做:

定義:dp [u][x]: 表示對於以 u 為根節點的子樹中,如果有 x 個空間(條邊)時候,能產生的最優值,

第一層 for 迴圈列舉 揹包空間 i(m>=i>=1)

第二層 for 迴圈列舉的給 u 的子節點 vi 分配的空間設為 j (這個空間分配這個空間所能得到的最優值為:dp [v][j]),那麼此時剩餘的空間為 i - j,此時還要在 減去乙個 1,因為如果我們要分配給 v 空間(邊數),那麼 u-vi 之間的邊 也占用乙個空間,所以最終剩餘的空間為 i - j -1, 對於這個剩餘的空間,所能得到的最優值為:在前 i-1 個物品(是 u 的子節點)空間為 i-j-1 的情況下所能得到的最優值是 dp [u][i - j - 1], 最後在加上 u - vi 這條的邊的權值(蘋果數量)w [u][vi] 就是最優解了

注意?上面只有 兩層 for 迴圈,但是在遞迴回溯的時候,會經過 / 遍歷 u 的所有子節點,這也相當於在地第一層 for 迴圈的外邊隱藏的一層 for 迴圈,而這一層 for 迴圈的作用是:列舉物品(子節點)

所以狀態轉移方程為:dp [u][i] = max (dp [u][i],dp [v][j]+dp [u][j-i-1]+w [u][v])

#include

#include

#include

#include

#include

#include

#include

#include

/* #include */

#include

#include

void

fre(

)void

fre(

)#define ios ios::sync_with_stdio(false)

#define pi acos(-1)

#define pb push_back

#define fi first

#define se second

#define ll long long

#define ull unsigned long long

#define db double

#define pir pair

#define m_p make_pair

#define inf 0x3f3f3f3f

#define esp 1e-7

#define for_(i, s, e) for(int i = (ll)(s); i <= (ll)(e); i ++)

#define rep_(i, e, s) for(int i = (ll)(e); i >= (ll)(s); i --)

#define sc scanf

#define pr printf

#define sd(a) scanf("%d", &a)

#define ss(a) scanf("%s", a)

#define size() size() * 1ll

#define mod (ll)(998244353)

#define min(a, b, c) min(a, min(b, c))

using namespace std;

const

int mxn =

105;

int dp[mxn]

[mxn]

;vector<

int> e[mxn]

;int w[mxn]

[mxn]

;int n, m;

void

dfs(

int u,

int p)

}int

main()

dfs(1,

0);pr

("%d\n"

, dp[1]

[m])

;return0;

}

1575 例 1 二叉蘋果樹

有一棵二叉蘋果樹,如果數字有分叉,一定是分兩叉,即沒有只有乙個兒子的節點。這棵樹共 n 個節點,標號 1 至 n,樹根編號一定為 1。我們用一根樹枝兩端連線的節點編號描述一根樹枝的位置。一棵有四根樹枝的蘋果樹,因為樹枝太多了,需要剪枝。但是一些樹枝上長有蘋果,給定需要保留的樹枝數量,求最多能留住多少...

二叉蘋果樹 樹形DP

題意 description 有一棵蘋果樹,如果樹枝有分叉,一定是分2叉 就是說沒有只有1個兒子的結點 這棵樹共有n個結點 葉子點或者樹枝分叉點 編號為1 n,樹根編號一定是1。我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹 2 5 3 4 1 現在這顆樹枝條太多了...

樹形DP 二叉蘋果樹

有一棵二叉蘋果樹,如果樹枝有分叉,一定是分兩叉,即沒有只有乙個兒子的節點。這棵樹共 n 個節點,編號為 1 至 n,樹根編號一定為 1。我們用一根樹枝兩端連線的節點編號描述一根樹枝的位置。一棵蘋果樹的樹枝太多了,需要剪枝。但是一些樹枝上長有蘋果,給定需要保留的樹枝數量,求最多能留住多少蘋果。這裡的保...