ZOJ3201 Tree of Tree 【树形dp】

来源:互联网 发布:手机标尺软件 编辑:程序博客网 时间:2024/05/17 05:55

题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3326

题意:在一颗树中找到大小为K的权值最大的子树

分析:典型的树形dp,转移方程dp[u][j]=max(dp[u][j],d[u][j-k]+dp[v][k]),dp[u][j]表示第u个点为子树根节点取子树大小为j的最大权值。这个方程比较好推,具体实现起来就是个背包的过程,但是不能按01背包的写法,需要按floyd的写法,不然会有点重复计算

代码:

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<vector>#include<cmath>#define N 105using namespace std;int dp[N][N],pre[N],val[N];int cnt,n,k;struct edge{    int v,next;}e[N*2];void add(int u,int v){    e[cnt].v=v;e[cnt].next=pre[u];    pre[u]=cnt++;}void dfs(int u,int p){    for(int i=0;i<=k;i++)dp[u][i]=-1;    dp[u][1]=val[u];    for(int i=pre[u];i!=-1;i=e[i].next){        int v=e[i].v;        if(v==p)continue;        dfs(v,u);        for(int j=k;j>=1;j--){            for(int l=1;l<=j;l++){                if(dp[u][l]==-1)continue;                dp[u][j]=max(dp[u][j],dp[u][l]+dp[v][j-l]);            }        }    }}int main(){    while(scanf("%d%d",&n,&k)!=EOF){        for(int i=0;i<n;i++)scanf("%d",&val[i]);        cnt=0;memset(pre,-1,sizeof(pre));        for(int i=1;i<n;i++){            int u,v;scanf("%d%d",&u,&v);            add(u,v);add(v,u);        }        dfs(0,0);int ans=0;        for(int i=0;i<n;i++)ans=max(ans,dp[i][k]);        printf("%d\n",ans);    }    return 0;}


0 0
原创粉丝点击