P2015 二叉蘋果樹
阿新 • • 發佈:2020-11-24
蘋果二叉樹
有一棵二叉蘋果樹,如果樹枝有分叉,一定是分兩叉,即沒有隻有一個兒子的節點。
這棵樹共 \(N\) 個節點,編號為 \(1\) 至 \(N\),樹根編號一定為 \(1\)。
我們用一根樹枝兩端連線的節點編號描述一根樹枝的位置。
一棵蘋果樹的樹枝太多了,需要剪枝。但是一些樹枝上長有蘋果,給定需要保留的樹枝數量,求最多能留住多少蘋果。
這裡的保留是指最終與1號點連通。
輸入格式
第一行包含兩個整數 \(N\) 和 \(Q\),分別表示樹的節點數以及要保留的樹枝數量。
接下來 \(N−1\) 行描述樹枝資訊,每行三個整數,前兩個是它連線的節點的編號,第三個數是這根樹枝上蘋果數量。
輸出格式
輸出僅一行,表示最多能留住的蘋果的數量。
資料範圍
\(1≤Q<N≤100\)
\(N≠1\)
每根樹枝上蘋果不超過 \(30000\) 個。
輸入樣例:
5 2
1 3 1
1 4 10
2 3 20
3 5 20
輸出樣例:
21
題解
樹形動態規劃沒得跑,
設\(f[u][j]\)表示\(u\)這個節點選擇\(j\)條邊的最大價值
每一棵子樹看出一組揹包,若需要選擇子樹\(son\)的時候,則根結點u到子樹\(son\)的邊一定用上,因此能用上的總邊數一定減\(1\),總共可以選擇\(j\)條邊時,當前子樹\(son\)分配的最大邊數是\(k\),那麼\(u\)為根的子樹的分配數量是\(j-k-1\)
\(f[u][j]=max(f[u][j],f[u][j-k-1]+f[v][k]+e[i])\)
#include<bits/stdc++.h> using namespace std; const int N=3000; int f[N][N]; int n,m; int ne[N],ver[N],head[N],idx,e[N]; void add(int u,int v,int w) { ne[idx]=head[u]; ver[idx]=v; head[u]=idx; e[idx]=w; idx++; } void dp(int x,int father) { for(int i=head[x];i!=-1;i=ne[i]) { int y=ver[i]; if(y==father)continue; dp(y,x); for(int j=m;j>=0;j--) { for(int k=0;k+1<=j;k++) { f[x][j]=max(f[x][j],f[x][j-k-1]+f[y][k]+e[i]); } } } } int main() { memset(head,-1,sizeof(head)); cin>>n>>m; for(int i=1;i<n;i++) { int a,b,c; cin>>a>>b>>c; add(a,b,c); add(b,a,c); } dp(1,0); cout<<f[1][m]<<endl; return 0; }