• ZOJ


    题意:有一棵树,树上每个结点都有一个权值,求恰好包含k个结点的子树的最大权值。

    设dp[i][j]为以结点i为根的树中包含j个结点的子树的最大权值,则可以把这个结点下的每棵子树中所包含的所有子树的大小当做物品的重量,对应的最大权值当做物品的价值,则相当于在它的每颗子树的所有物品中任选一个进行更新,对每个状态取最大价值。

    状态转移方程:$dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k])$

    注:由于每棵子树下只能选一件物品,所以应当先枚举状态再枚举物品,这样就避免了同一棵子树下状态的累加。

    复杂度$O(n^3)$,可用siz数组确定上界优化到$O(n^2)$。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int N=100+10;
     5 int hd[N],a[N],ne,n,k,dp[N][N],siz[N];
     6 struct E {int v,nxt;} e[N<<1];
     7 void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;}
     8 void dfs(int u,int fa) {
     9     memset(dp[u],-1,sizeof dp[u]);
    10     siz[u]=1,dp[u][1]=a[u];
    11     for(int i=hd[u]; ~i; i=e[i].nxt) {
    12         int v=e[i].v;
    13         if(v==fa)continue;
    14         dfs(v,u);
    15         for(int j=siz[u]; j>=0; --j)if(~dp[u][j])
    16                 for(int k=0; k<=siz[v]; ++k)if(~dp[v][k])
    17                         dp[u][j+k]=max(dp[u][j+k],dp[u][j]+dp[v][k]);
    18         siz[u]+=siz[v];
    19     }
    20 }
    21 
    22 int main() {
    23     while(scanf("%d%d",&n,&k)==2) {
    24         memset(hd,-1,sizeof hd),ne=0;
    25         for(int i=0; i<n; ++i)scanf("%d",&a[i]);
    26         for(int i=0; i<n-1; ++i) {
    27             int u,v;
    28             scanf("%d%d",&u,&v);
    29             addedge(u,v);
    30             addedge(v,u);
    31         }
    32         dfs(0,-1);
    33         int ans=0;
    34         for(int i=0; i<n; ++i)ans=max(ans,dp[i][k]);
    35         printf("%d
    ",ans);
    36     }
    37     return 0;
    38 }
  • 相关阅读:
    android之View绘制到窗口上的过程
    Java设计模式-回调函数和观察者模式
    Android视图加载到窗口的过程分析
    Android中Handler原理
    第五百二十九天 how can I 坚持
    第五百二十至五百二十八天 how can I 坚持
    第五百一十九天 how can I 坚持
    第五百一十八天 how can I 坚持
    第五百一十七天 how can I 坚持
    第五百一十六天 how can I 坚持
  • 原文地址:https://www.cnblogs.com/asdfsag/p/10526078.html
Copyright © 2020-2023  润新知