P3177 [HAOI2015]树上染色

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

说明

对于\(100%\)的数据,\(0<=K<=N <=2000\)


这里阐述一下我的思考方式。

首先,真的一下子想到贪心去了。前几天做了消防,觉得在树的直径上会有一些奇妙优美的性质,遂开始想办法证明。

然后考试完了还在证贪心\(emmmm\)。

解法很容易懂,但是很难想(我太蒻了)


正解是树形\(DP\)

令\(dp[i][j]\)为以\(i\)为根节点的子树中 在染了\(j\)个黑点时 所有的边再加上\(i\)头上的那个边 对整颗树 的答案贡献

有灵性就有灵性在这个整颗树上

在已经处理好子树\(v\)时,我们加入边\(E_k(u,v)\)(\(u\)为\(v\)的父亲)

则\(E_k\)的贡献即为边权\(w*\)子树\(u\)中白点个数子树\(u\)外面的数白点个数\(+w*\)子树\(u\)中黑点个数子树\(u\)外面的数黑点个数,这点不难想明白

当然,不做头顶上的边也是可以的,但很多树形\(dp\)管一下自己的脑门是比较方便的

转移时,我们对每棵子树做树上分组背包,最后在判断一下她自己头上的边


code

#include <cstdio>
#include <cstring>
#define ll long long
ll max(ll x,ll y) {return x>y?x:y;}
ll min(ll x,ll y) {return x<y?x:y;}
const int N=2001;
ll dp[N][N];
//根节点为i的子树j个点染黑所有边的最大答案
ll n,k;
struct Edge
{
    ll to,next,w;
}edge[N*2];
ll head[N],cnt=0;
void add(ll u,ll v,ll w)
{
    edge[++cnt].to=v;
    edge[cnt].next=head[u];
    edge[cnt].w=w;
    head[u]=cnt;
}
int used[N];
ll dfs(ll u,ll c)
{
    used[u]=1;
    ll size=0;
    memset(dp[u],-1,sizeof(dp[u]));
    dp[u][0]=0;
    for(ll i=head[u];i;i=edge[i].next)
    {
        ll v=edge[i].to,w=edge[i].w;
        if(!used[v])
        {
            ll si=dfs(v,w);size+=si;
            for(ll j=min(k,size);j>=0;j--)
            {
                ll r=min(j,min(si,k));
                for(ll k0=0;k0<=r;k0++)
                    if(dp[u][j-k0]!=-1)
                        dp[u][j]=max(dp[u][j],dp[u][j-k0]+dp[v][k0]);
            }
        }
    }
    size++;
    ll l=max(size+k-n,1);
    for(ll i=min(k,size);i>=l;i--)
    {
        ll cc=c*(k-i)*i+c*(n-size-k+i)*(size-i);
        dp[u][i]=max(dp[u][i],dp[u][i-1])+cc;
    }
    l=size+k-n;
    dp[u][0]+=c*(n-size-k)*size;
    return size;
}

int main()
{
    scanf("%lld%lld",&n,&k);
    ll u,v,w;
    for(ll i=1;i<n;i++)
    {
        scanf("%lld%lld%lld",&u,&v,&w);
        add(u,v,w),add(v,u,w);
    }
    dfs(1,0);
    printf("%lld\n",dp[1][k]);
    return 0;
}

细节问题:

1.分组背包转移方程为:\(dp[u][j]=max(dp[u][j],dp[u][j-k0]+dp[v][k0])\)

我们一定要判断\(dp[u][j-k0]\)的合法性

2.开\(long long\)不要吝啬空间(除非卡的太死,反正也就两倍),能看尽量就开,只开一部分在计算时真的不注意就可能丢失了或者爆了

3.背包的上下界,最好加上,不然常数一大可能会\(t\)。有的不加甚至会出现一些问题。


2018.5.15

洛谷 P3177 树上染色 解题报告的更多相关文章

  1. 洛谷 P2664 树上游戏 解题报告

    P2664 树上游戏 题目描述 \(\text{lrb}\)有一棵树,树的每个节点有个颜色.给一个长度为\(n\)的颜色序列,定义\(s(i,j)\) 为 \(i\) 到 \(j\) 的颜色数量.以及 ...

  2. 洛谷 P3177 树上染色

    题面 题目要求将k个点染成黑色,求黑点两两距离及白点两两距离,使他们之和最大. 我们可以将距离转化为路径,然后再将路径路径拆分成边,就可以记录每条边被经过的次数,直接计算即可. 很简单对吧?那么问题来 ...

  3. 洛谷P3177 树上染色

    题目 一道非常好的树形DP. 状态:\(dp[u][n]\)为u的子树选n个黑点所能得到的收益最大值. 则最终的结果就是\(dp[root][k],\)\(root\)可以为任何值,为了方便,使\(r ...

  4. 洛谷 P1783 海滩防御 解题报告

    P1783 海滩防御 题目描述 WLP同学最近迷上了一款网络联机对战游戏(终于知道为毛JOHNKRAM每天刷洛谷效率那么低了),但是他却为了这个游戏很苦恼,因为他在海边的造船厂和仓库总是被敌方派人偷袭 ...

  5. 洛谷 P4597 序列sequence 解题报告

    P4597 序列sequence 题目背景 原题\(\tt{cf13c}\)数据加强版 题目描述 给定一个序列,每次操作可以把某个数\(+1\)或\(-1\).要求把序列变成非降数列.而且要求修改后的 ...

  6. 洛谷1087 FBI树 解题报告

    洛谷1087 FBI树 本题地址:http://www.luogu.org/problem/show?pid=1087 题目描述 我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全 ...

  7. 洛谷 P4211 [LNOI2014]LCA 解题报告

    [LNOI2014]LCA 题意 给一个\(n(\le 50000)\)节点的有根树,询问\(l,r,z\),求\(\sum_{l\le i\le r}dep[lca(i,z)]\) 一直想启发式合并 ...

  8. 洛谷 P2680 运输计划 解题报告

    P2680 运输计划 题目背景 公元2044年,人类进入了宇宙纪元. 题目描述 公元2044年,人类进入了宇宙纪元. \(L\)国有\(n\)个星球,还有\(n-1\)条双向航道,每条航道建立在两个星 ...

  9. 洛谷 P2245 星际导航 解题报告

    P2245 星际导航 题目描述 sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为了方便起见,我们可以认为宇宙是一张有N 个顶点和M 条边的带权无向 ...

随机推荐

  1. Unity 5.X扩展编辑器之打包assetbundle

    5.x的assetbundle与4.x以及之前的版本有些不同,不过本质是一样的,只不过5.x打包assetbundle更为简单和人性化了,总体来说只需要三个步骤: 第一步:创建打包资源 //这里是一个 ...

  2. 《java入门第一季》之面向对象面试题(this和super的区别)

    this和super的区别? 分别是什么呢? this代表本类对象的引用. super代表父类存储空间的标识(可以理解为父类引用,可以操作父类的成员) 怎么用呢? A:调用成员变量 this.成员变量 ...

  3. RTMPdump(libRTMP) 源代码分析 6: 建立一个流媒体连接 (NetStream部分 1)

    ===================================================== RTMPdump(libRTMP) 源代码分析系列文章: RTMPdump 源代码分析 1: ...

  4. 速度之王 — LZ4压缩算法(一)

    LZ4 (Extremely Fast Compression algorithm) 项目:http://code.google.com/p/lz4/ 作者:Yann Collet 本文作者:zhan ...

  5. 如果以一个树状的形式返回一个UIView的所有子视图

    该方法也是从一个视频中看到,总觉得会有很大作用,故记录在这里. 它返回一个xml的字符串,用火狐浏览器或者其他可以格式化xml的工具打开,即可查看其层级关系. /** * 返回传入view的所有层级结 ...

  6. 初探linux子系统集之写在前言

    毕业两周年,进入嵌入式linux这个行业也已两个年头有余,从开始的linux驱动,android的framework,到现在的linux应用,android的app以及产品的零零总总,其实很想把这些都 ...

  7. 复位windows网络参数的方法

    使用电脑的时候,经常会遇到网络相关的问题,以前读大学的时候就知道怎么解决,就是下面这个方案. 开始-全部程序-附件-命令提示符-右键-以管理员身份运行出来一个黑底白字的窗口,在里面输入: netsh ...

  8. sql中的case when then else end

    hive中的case when的用法举例 select * from (select id, count(distinct ] in ("Virus","Worm&quo ...

  9. Construct Binary Tree from Preorder and Inorder Traversal(根据前序中序构建二叉树)

    根据前序中序构建二叉树. 1 / \ 2 3 / \ / \ 4 5 6 7对于上图的树来说, index: 0 1 2 3 4 5 6 先序遍历为: 6 3 7为了清晰表示,我给节点上了颜色,红色是 ...

  10. Swap Nodes in Pairs(交换节点)

    Given a linked list, swap every two adjacent nodes and return its head. For example,Given 1->2-&g ...