1. 程式人生 > >【codevs】二叉蘋果樹 (二叉樹的樹形dp)

【codevs】二叉蘋果樹 (二叉樹的樹形dp)

P2015 二叉蘋果樹

題目描述

有一棵蘋果樹,如果樹枝有分叉,一定是分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。瞎搞就可以。 注:因為這道題給的兩個點之間前後順序是不一定的,所以首先判斷其中一點是不是其他節點的子節點,若是,則將其作為另一節點的父親,反之則為兒子節點。

附程式碼:

#include<iostream>
#include<cstdio>
using namespace
std; struct node { int l,r,v; }tree[1001]; int flag[101]; int f[101][101]; int n,q; int gen; void ecs() { int i,x,y,m; for (i=1;i<n;i++) { int p=0; scanf("%d%d%d",&x,&y,&m); for (int j=1;j<=n;j++) if (tree[j].l==y||tree[j].r==y) p=1; //因為這道題給的兩個點之間前後順序是不一定的,所以首先判斷其中一點
//是不是其他節點的子節點,若是,則將其作為另一節點的父親,反之則為兒子節點。 if (p==0) { if (tree[x].l==0) tree[x].l=y; else if (tree[x].r==0) tree[x].r=y; tree[y].v=m; flag[y]=1; } else { if (tree[y].l==0) tree[y].l=x; else if (tree[y].r==0) tree[y].r=x; tree[x].v=m; flag[x]=1; } } for (i=1;i<=n;i++) if (flag[i]==0) {gen=i;break;} } void dfs(int i,int j) { int k; if (j==0) f[i][j]=0; else if (tree[i].r==0&&tree[i].l==0) f[i][j]=tree[i].v; else { f[i][j]=0; for (k=0;k<j;k++) { if (f[tree[i].l][k]==0) dfs(tree[i].l,k); if (f[tree[i].r][j-k-1]==0) dfs(tree[i].r,j-k-1); f[i][j]=max(f[i][j],f[tree[i].l][k]+f[tree[i].r][j-k-1]+tree[i].v); } } } int main() { int ans; scanf("%d%d",&n,&q); ecs(); dfs(gen,q+1); printf("%d",f[gen][q+1]);//q+1是因為將價值賦值給了父節點與子節點的子節點,所以最後是q+1 }