zoukankan      html  css  js  c++  java
  • bzoj4033

    传送门:https://www.vijos.org/d/newbzoj/p/590c98b5d3d8a13210993839
    试题描述:
    有一棵点数为N的树,树边有边权。给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并
    将其他的N-K个点染成白色。将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的和的收益。
    问收益最大值是多少。

    输入示例

    5 2
    1 2 3
    1 5 1
    2 3 1
    2 4 2

    输出示例

    17
    解题思路:
    设dp[i][j]是以i为根的子树中j个节点被染黑时所得到的边的最大贡献,这里的贡献是全局的,有dp[u][0]=dp[u][1]=0(因为无边)。枚举每一个子树被染黑的个数,通过连接根节点和子树的边进行状态转移。
    注意遍历要从高遍历到0,防止遍历覆盖造成答案变大
    dp[u][y+i]=max(dp[u][y+i],dp[u][y]+dp[j][i]+w[p]*((ll)i*(k-i)+((ll)sum[j]-i)*(n-k-sum[j]+i)));//dp[u][y]表示其他已经枚举过的子树中有y个黑节点时的最大值
     1 #include<iostream>
     2 #include<cstring>
     3 #define ll long long
     4 using namespace std;
     5 int n,k;
     6 int h[2010],e[4010],ne[4010],idx;
     7 ll w[4010];int sum[2010];
     8 ll dp[2010][2010];
     9 void add(int a,int b,ll c)
    10 {
    11     ne[idx]=h[a];
    12     w[idx]=c;
    13     e[idx]=b;
    14     h[a]=idx++;
    15 }
    16 void dfs(int u,int fa)
    17 {
    18     sum[u]=1;int res=1;//res表示已经枚举过多少个子节点(res<=k)
    19     dp[u][0]=dp[u][1]=0;
    20     for(int p=h[u];p!=-1;p=ne[p])
    21     {
    22         int j=e[p];
    23         if(j!=fa)
    24         {
    25             dfs(j,u);
    26             sum[u]+=sum[j];
    27             for(int y=res;y>=0;y--)//枚举已经遍历过的子树中有多少黑节点
    28              for(int i=min(k,sum[j]);i>=0;i--)
    29                  if(y+i<=k)
    30         //dp[u][k+i] = max(dp[u][k+i], dp[j][i] + dp[u][k] + w[p] * ((ll)i * (k - i) + ((ll)sum[j] - i) * (n - k - sum[j] + i)));
    31                      dp[u][y+i]=max(dp[u][y+i],dp[u][y]+dp[j][i]+w[p]*((ll)i*(k-i)+((ll)sum[j]-i)*(n-k-sum[j]+i)));
    32            res=min(k,res+sum[j]);
    33         }
    34     }
    35 }
    36 int main()
    37 {
    38     memset(h,-1,sizeof h);
    39     cin>>n>>k;
    40     for(int i=1;i<n;i++)
    41     {
    42         int a,b;ll c;
    43         cin>>a>>b>>c;
    44         add(a,b,c);
    45         add(b,a,c);
    46     }
    47     dfs(1,0);
    48     printf("%lld
    ",dp[1][k]);
    49     return 0;
    50 }
  • 相关阅读:
    python中的system函数与编码
    使用signal、setjmp、longjmp进行Linux/Android C异常处理
    ffffffuzzzzzzzzzzzzing
    EIGRP汇总
    JDK
    世界上最健康的生活方式
    Oracle 取两个表中数据的交集并集差异集合
    信息科技风险管理
    BPDU与PortFast
    大胆发言
  • 原文地址:https://www.cnblogs.com/flyljz/p/11955066.html
Copyright © 2011-2022 走看看