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. ceres-solver库使用示例

    上一篇博客大致说明了下ceres-solver库的编译,然后形成了一个二次开发的库,下面就是用这个二次开发库来写一个简单(其实不太简单)的DEMO来演示ceres-solver库的强大.我们以求解一个 ...

  2. Java进阶(二十二)使用FileOutputStream写入文件

    Java使用FileOutputStream写入文件 绪 在Java中,文件输出流是一种用于处理原始二进制数据的字节流类.为了将数据写入到文件中,必须将数据转换为字节,并保存到文件.请参阅下面的完整的 ...

  3. 禁用JavaScript控制台调试

    原文链接: Disable the User's JavaScript Console 原文日期: 2014年03月06日 翻译日期: 2014年03月07日 翻译人员: 铁锚 有几个巨头公司,即Fa ...

  4. 一张图了解cocos2d坐标系

    一张图了解cocos2d坐标系 平面直角坐标系

  5. apktool动态破解apk

    那么今天我们就用另外一种方式来破解apk:动态方式,关于动态方式其实很广义的,因为动态方式相对于静态方式来说,难度大一点,但是他比静态方式高效点,能够针对更过的破解范围.当然动态方式很多,所以这里就分 ...

  6. x64系统的判断和x64下文件和注册表访问的重定向——补记

    原来的地址 x64系统的判断和x64下文件和注册表访问的重定向(1) x64系统的判断和x64下文件和注册表访问的重定向(2) x64系统的判断和x64下文件和注册表访问的重定向(3) 之前在(3)里 ...

  7. navicat为mysql建立索引

    索引的目的是大大提高查询效率,还有读写效率. kettle向sql里面插入,更新时,也要建立索引,可以大大提升处理时间. 但是建立索引报错:Specified key was too long; ma ...

  8. 瑞芯微RK3188如何配置USB摄像头支持

  9. 快速熟悉Oracle索引

    一.索引 1.1 什么是索引? 一种用于提升查询效率的数据库对象: 通过快速定位数据的方法,减少磁盘的输入输出操作: 索引信息与表独立存放: Oracle数据库自动使用和维护索引. 1.2 索引分类 ...

  10. 用windbg显示特定进程虚拟地址的方法

    1 必须使用Livekd.exe启动windbg 2 !process PID 3 找到PROCESS对象的地址:PROCADDR 4 找到进程的DirBase 5 r cr3 = DirBase 6 ...