1. 程式人生 > >洛谷2015二叉蘋果樹

洛谷2015二叉蘋果樹

題目描述

有一棵蘋果樹,如果樹枝有分叉,一定是分2叉(就是說沒有隻有1個兒子的結點)

這棵樹共有N個結點(葉子點或者樹枝分叉點),編號為1-N,樹根編號一定是1。

我們用一根樹枝兩端連線的結點的編號來描述一根樹枝的位置。下面是一顆有4個樹枝的樹

2   5
 \ / 
  3   4
   \ /
    1

現在這顆樹枝條太多了,需要剪枝。但是一些樹枝上長有蘋果。

給定需要保留的樹枝數量,求出最多能留住多少蘋果。

輸入輸出格式

輸入格式:

 

第1行2個數,N和Q(1<=Q<= N,1<N<=100)。

N表示樹的結點數,Q表示要保留的樹枝數量。接下來N-1行描述樹枝的資訊。

每行3個整數,前兩個是它連線的結點的編號。第3個數是這根樹枝上蘋果的數量。

每根樹枝上的蘋果不超過30000個。

 

輸出格式:

 

一個數,最多能留住的蘋果的數量。

 

輸入輸出樣例

輸入樣例#1: 複製
5 2
1 3 1
1 4 10
2 3 20
3 5 20
輸出樣例#1: 複製
21

***這是一個由根分成左子樹和右子樹兩部分的情況的樹型DP
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4
#include<algorithm> 5 using namespace std; 6 int i,j,n,q,l[105],r[105],f[105][105] = {0},map[105][105],a[105];//f[i][j]代表以i為節點保留j個節點的最大權值和 7 void buildtree(int v) //建樹 8 { 9 for(int i = 1;i <= n;i++) 10 { 11 if(map[v][i] >= 0) //左子樹 12 { 13 l[v] = i; 14 a[i] = map[v][i];
15 map[v][i] = -1; 16 map[i][v]= map[v][i]; //標記訪問 17 buildtree(i); 18 break; 19 } 20 } 21 for(i = 1;i <= n;i++) 22 { 23 if(map[v][i] >= 0) //右子樹 24 { 25 r[v] = i; 26 a[i] = map[v][i]; 27 map[v][i] = -1; 28 map[i][v] = map[v][i]; //標記訪問 29 buildtree(i); 30 break; 31 } 32 } 33 } 34 int DP(int i,int j) //樹型DP,記憶化搜尋 35 { 36 if(j == 0) 37 return 0; 38 if((l[i] == 0) && (r[i] == 0)) 39 return a[i]; // 葉子節點 40 if(f[i][j] > 0) 41 return f[i][j]; // 已經計算 42 for(int k = 0;k <= j - 1;k++) 43 { 44 f[i][j] = max(f[i][j],DP(l[i],k) + DP(r[i],j - k - 1) + a[i]); 45 } 46 return f[i][j]; 47 } 48 int main() 49 { 50 int x,y,z; 51 scanf("%d %d",&n,&q); 52 q = q + 1; 53 for(i = 1;i <= n;i++) 54 { 55 for(j = 1;j <= n;j++) 56 { 57 map[i][j] = -1; 58 } 59 } 60 for(i = 1;i <= n - 1;i++) 61 { 62 scanf("%d %d %d",&x,&y,&z); 63 map[x][y] = z; 64 map[y][x] = map[x][y]; 65 } 66 buildtree(1); // 以1為根建立二叉樹 67 printf("%d",DP(1,q)); 68 return 0; 69 }