【codevs】二叉蘋果樹 (二叉樹的樹形dp)
阿新 • • 發佈:2019-01-27
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
}