題目描述
有一棵蘋果樹,如果樹枝有分叉,一定是分2叉(就是說沒有只有1個兒子的結點)。這棵樹共有n個結點(葉子點或者樹枝分叉點),編號為1-n,樹根編號一定是1。 我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹:
2 53 4
現在這顆樹枝條太多了,需要剪枝。但是一些樹枝上長有蘋果。 給定需要保留的樹枝數量,求出最多能留住多少蘋果。
輸入格式
第1行2個數,n和q(1<=q<= n,1輸出格式
乙個數,最多能留住的蘋果的數量。
這道題就是一道典型的二維樹形dp問題。
設f [i
][j]
f[i][j]
f[i][j
]表示在以i
ii為根的子樹中,保留了j
jj個枝條所保留的最大蘋果。
狀態轉移方程:f[x
][i]
=max
(f[y
][j]
+val
(x,y
)+f[
x][i
−j−1
]),y
∈son
(i
)f[x][i]=max(f[y][j]+val(x,y)+f[x][i-j-1]),\ y∈son(i)
f[x][i
]=ma
x(f[
y][j
]+va
l(x,
y)+f
[x][
i−j−
1]),
y∈so
n(i)
相信狀態轉移方程十分清楚明白,這裡的f[x
][i−
j−1]
f[x][i-j-1]
f[x][i
−j−1
]顯然是先前已經列舉過的其它子樹。
我們此時需要求出i和j的取值範圍,通過仔細畫圖可以得知:
1 ≤i
≤min
(siz
e[x]
−1,q
)1≤i≤min(size[x]-1,q)
1≤i≤mi
n(si
ze[x
]−1,
q)0 ≤j
≤min
(siz
e[y]
−1,i
−1
)0≤j≤min(size[y]-1,i-1)
0≤j≤mi
n(si
ze[y
]−1,
i−1)
注意狀態轉移方程i
ii和j
jj需要逆序列舉,原理同01揹包
01揹包
01揹包
,f [x
][i−
j−1]
f[x][i-j-1]
f[x][i
−j−1
]是同一棵子樹的轉移。
**如下:
#include
#define mp make_pair
using
namespace std;
int n,q;
int size[
200]
;vector< pair<
int,
int>
>a[
200]
;int f[
200]
[200];
void
getsize
(int x,
int fa)
}voiddp(
int x,
int fa)
}int
main
(void
)getsize(1
,0);
dp(1,
0);printf
("%d"
,f[1
][q]);
return0;
}
藍橋杯訓練 動態規劃 蘋果二叉樹
問題描述 二叉蘋果樹 題目描述 有一棵蘋果樹,如果樹枝有分叉,一定是分2叉 就是說沒有只有1個兒子的結點 這棵樹共有n個結點 葉子點或者樹枝分叉點 編號為1 n,樹根編號一定是1。我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹 2 5 3 4 1 現在這顆樹枝條太多...
樹形dp ural1018蘋果二叉樹
include include include include include include define maxn 200 define inf 0xfffffff using namespace std int dp maxn maxn dp i j 表示以i為根取j條樹枝的最大值 1.只有乙...
二叉樹習題之重建二叉樹
對於給定前序和中序的重建方法。1 前序的第乙個元素一定是樹的根節點,在中序集合中找到此元素,那麼該元素的左面即為根的左子樹,右面為右子樹。2 找到前序的第二個元素,重複上面的步驟。自寫程式的效率大概為 n n 2 或最大的那個元素 這點很坑,斟酌改掉 目前沒發現更快的寫法 自己寫 結果以連續記憶體的...