• BZOJ 4033[HAOI2015] 树上染色(树形DP)


    4033: [HAOI2015]树上染色

    Time Limit: 10 Sec  Memory Limit: 256 MB
    Submit: 3188  Solved: 1366
    [Submit][Status][Discuss]

    Description

    有一棵点数为N的树,树边有边权。给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并
    将其他的N-K个点染成白色。将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的和的收益。
    问收益最大值是多少。

    Input

    第一行两个整数N,K。
    接下来N-1行每行三个正整数fr,to,dis,表示该树中存在一条长度为dis的边(fr,to)。
    输入保证所有点之间是联通的。
    N<=2000,0<=K<=N

    Output

    输出一个正整数,表示收益的最大值。

    Sample Input

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

    Sample Output

    17
    【样例解释】
    将点1,2染黑就能获得最大收益。

    HINT

    2017.9.12新加数据一组 By GXZlegend

    题解

    这题还是可以的。

    我们用dp[i][j]代表i的子树中有j个黑点时子树中的边(如果不是整棵树的根节点也包括这个根节点和父亲的边)的最大贡献。

    设这条边权为w,把整棵树分为x,y两部分 所以一条边的贡献为 边的长度*(x中的白点数*y中的白点数+x中的黑点数*y中的黑点数)

    所以转化为了背包问题。每颗子树选不同的黑点有不同的权值。

    然后最后加上当前子树根节点的贡献

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cmath>
     5 #include<algorithm>
     6 using namespace std;
     7 const long long N=2010;
     8 long long n,k,cnt,head[N],size[N],dp[N][N*2];
     9 struct edge{
    10     long long  to,nxt,w;
    11 }e[N*2];
    12 void add(long long u,long long v,long long w){
    13     cnt++;
    14     e[cnt].nxt=head[u];
    15     e[cnt].to=v;
    16     e[cnt].w=w;
    17     head[u]=cnt;
    18 }
    19 void getdp(long long u,long long fa,long long w){
    20     size[u]=1;
    21     for(long long i=head[u];i;i=e[i].nxt){
    22         long long v=e[i].to;
    23         if(v==fa)continue;
    24         getdp(v,u,e[i].w); 
    25         for(long long j=min(k,size[u]);j>=0;j--)
    26             for(long long z=min(size[v],k-j);z>=0;z--){
    27                 dp[u][j+z]=max(dp[u][j+z],dp[u][j]+dp[v][z]);
    28             }
    29         size[u]+=size[v];
    30     }
    31     for(long long i=0;i<=min(k,size[u]);i++)dp[u][i]+=w*((size[u]-i)*(n-k-(size[u]-i))+i*(k-i));
    32 }
    33 int main(){
    34     scanf("%lld%lld",&n,&k);
    35     for(long long i=2;i<=n;i++){
    36         long long u,v,w;
    37         scanf("%lld%lld%lld",&u,&v,&w);
    38         add(u,v,w);
    39         add(v,u,w);
    40     }
    41     getdp(1,0,0);
    42     printf("%lld",dp[1][k]);
    43     return 0;
    44 }
  • 相关阅读:
    KVC与KVO的进阶使用
    Qt之图形视图框架
    Qt之QRoundProgressBar(圆形进度条)
    Qt之绘制闪烁文本
    Qt之QCustomPlot(图形库)
    Qt之事件系统
    iOS 保持界面流畅的技巧
    iOS开发数据库SQLite的使用
    Qt之保持GUI响应
    Qt之QSS(QDarkStyleSheet)
  • 原文地址:https://www.cnblogs.com/Xu-daxia/p/9587789.html
Copyright © 2020-2023  润新知