ZOJ 3201 Tree of Tree(树形背包DP)

来源:互联网 发布:sql exists用法 编辑:程序博客网 时间:2024/04/30 02:19

dp[i][j]表示在i结点上选择j个结点能获得的最大值,j的值最大自然是以i为根的子树的结点数量.

dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[v][k])//方程意义就是在i结点上选择j个点的最优值等于 max(当前值,在i的一颗子树上选择j-k个结点+在i的子树v上选择k个点) (k=1 2 ... j-1).枚举j和k.

j-1因为必须要把i算进去

#include <iostream>#include <memory.h>#include <cstdio>using namespace std;const int maxn=101;struct edge{int v,next;}es[maxn*2];int head[maxn],dp[maxn][maxn],v[maxn],N,K;void addEdge(int u,int v,int eidx){es[eidx].v=v;es[eidx].next=head[u];head[u]=eidx;}int dfs(int u,int fa){dp[u][1]=v[u];int tot=1;for (int ne=head[u];ne!=-1;ne=es[ne].next){int v=es[ne].v;if(v==fa)continue;tot+=dfs(v,u);for (int j=tot;j>=1;--j){for (int k=1;j-k>=1;++k){dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]);}}}return tot;}int main(){while (scanf("%d%d",&N,&K)==2){memset(dp,0,sizeof(dp));memset(head,-1,sizeof(head));for (int i=0;i<N;++i){scanf("%d",&v[i]);}int eidx=0;for (int i=0;i<N-1;++i){int u,v;scanf("%d%d",&u,&v);addEdge(u,v,eidx++),addEdge(v,u,eidx++);}dfs(0,-1);int ans=0;for (int i=0;i<N;++i){ans=max(ans,dp[i][K]);}printf("%d\n",ans);}return 0;}


原创粉丝点击