题目:
题目背景
URAL:http://acm.timus.ru/problem.aspx?space=1&num=1018
题目描述
有一棵苹果树,如果树枝有分叉,一定是分 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
输出
21
题解:
dp[i][j]:表示i号点所在子树(包括自己)共保留j个点可以留下的最多苹果
注意这道题我把保留m条边变成保留m+1个点来求的·····
另外注意在进行树形dp dfs的时候用记忆化搜索·····
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> #include<cctype> #include<cstring> #include<string> #include<algorithm> using namespace std; const int N=105; int first[N],next[N*2],go[N*2],val[N*2],tot; int n,m; int dp[N][N]; inline void comb(int a,int b,int c) { next[++tot]=first[a],first[a]=tot,go[tot]=b,val[tot]=c; next[++tot]=first[b],first[b]=tot,go[tot]=a,val[tot]=c; } inline void dfs(int u,int fa,int Val,int k) { if(u==0||k==0) { dp[u][k]=0; return; } if(dp[u][k]!=-1) return; dp[u][k]=0; for(int i=0;i<k;i++) { int l=0,r=0,vl,vr; for(int e=first[u];e;e=next[e]) { int v=go[e]; if(v==fa) continue; if(l==0) l=v,vl=val[e]; else { r=v,vr=val[e]; break; } } dfs(l,u,vl,i); dfs(r,u,vr,k-i-1); dp[u][k]=max(dp[l][i]+dp[r][k-i-1]+Val,dp[u][k]); } return; } int main() { freopen("a.in","r",stdin); scanf("%d%d",&n,&m); m++; memset(dp,-1,sizeof(dp)); int a,b,c; for(int i=1;i<n;i++) { scanf("%d%d%d",&a,&b,&c); comb(a,b,c); } dfs(1,0,0,m); cout<<dp[1][m]<<endl; return 0; }
时间: 2024-10-05 11:42:55