zoj3201(树形dp)

时间:2023-03-10 02:29:22
zoj3201(树形dp)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3201

题意:给一棵树, n结点<=1000, 和K <=200,  找这棵树上找大小为k的子树, 使其点权值最大。

分析:dp[u][j]表示以点u为根节点的子树含有j个节点的最大值,dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]).

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define LL long long
#define mod 1000000007
#define inf 0x3f3f3f3f
#define N 110
#define clr(a) (memset(a,0,sizeof(a)))
using namespace std;
struct edge
{
int next,v;
edge(){}
edge(int v,int next):v(v),next(next){}
}e[N*];
int head[N],tot,n,m;
int dp[N][N],val[N];
void addedge(int u,int v)
{
e[tot]=edge(v,head[u]);
head[u]=tot++;
}
void dfs(int u,int fa)
{
for(int i=;i<=m;i++)dp[u][i]=val[u];
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].v;
if(v==fa)continue;
dfs(v,u);
for(int j=m;j>=;j--)
for(int k=;k<j;k++)//肯定得含有节点u,所以k<j.
dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]);
}
}
int main()
{
int u,v;
while(scanf("%d%d",&n,&m)>)
{
tot=;
memset(head,-,sizeof(head));clr(dp);
for(int i=;i<n;i++)scanf("%d",&val[i]);
for(int i=;i<n;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dfs(,-);
int ans=;
for(int i=;i<n;i++)ans=max(ans,dp[i][m]);
printf("%d\n",ans);
}
}