标签:二叉苹果树树型dp+背包
二叉苹果树1
现在这颗树枝条太多了,需要剪枝。但是一些树枝上长有苹果。
给定需要保留的树枝数量,求出最多能留住多少苹果。每根树枝上的苹果不超过30000个。
输出格式:
一个数,最多能留住的苹果的数量。输入样例:
5 221
解题思路:树型DP+背包求解。
f(i, j) 表示子树i,保留j个节点(注意是节点)的最大权值。每条边的权值,把它看作是连接的两个节点中的儿子节点的权值。
那么,就可以对所有i的子树做分组背包,即每个子树可以选择1,2,...j-1条边分配给它。
状态转移为:
f(i, j) = max{ max{f(i, j-k) + f(v, k) | 1<=k<j} | v是i的儿子}
ans = f(1, q+1)
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define MAX 105
#define INF 999999999
#define MP make_pair
typedef pair<int,int> PII;
vector<PII> adj[MAX];
int tot[MAX],f[MAX][MAX];
int max(int a,int b)
{
return a>b?a:b;
}
int DFS(int u,int ff)
{
tot[u]=1;
int i,j,k;
for(i=0;i<adj[u].size();i++)
{
int v=adj[u][i].first;
if(v==ff)
continue;
tot[u]+=DFS(v,u);
}
for(i=0;i<adj[u].size();i++)
{
int v=adj[u][i].first;
int w=adj[u][i].second;
if(v==ff)
continue;
for(j=tot[u];j>1;j--)
{
for(k=1;(k<j)&&(k<=tot[v]);k++)
f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]+w);
}
}
return tot[u];
}
int main()
{
int i;
int n,p,u,v,w;
while(~scanf("%d%d",&n,&p))
{
for(i=0;i<MAX;i++)
adj[i].clear();
for(i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&w);
adj[u].push_back(MP(v,w));
adj[v].push_back(MP(u,w));
}
memset(f,0,sizeof(f));
DFS(1,-1);
printf("%d\n",f[1][p+1]);
}
return 0;
}标签:二叉苹果树树型dp+背包
原文地址:http://blog.csdn.net/u012804490/article/details/25782757