[HAOI2015]树上染色(树形背包)
有一棵点数为 N 的树,树边有边权。给你一个在 0~ N 之内的正整数 K ,你要在这棵树中选择 K个点,将其染成黑色,并将其他 的N-K个点染成白色 。 将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间的距离的和的受益。问受益最大值是多少。
Solution
比较经典的树形背包问题。
如果只对点进行分析,情况会变得十分麻烦,不放考虑每条变的贡献,每条边会产生两边黑点数的乘积加上两边白点数的乘积。
这样的话我们直接跑背包就可以了,标准的树形背包是n^3的,但是这道题每颗字数背包体积有上限,总复杂度可以做到n^2.
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 2009
using namespace std;
long long dp[N][N];
int size[N],m,n,a,b,c,tot,head[N];
struct dsd
{
int n,to,l;
}an[N<<];
inline void add(int u,int v,int l)
{
an[++tot].n=head[u];
an[tot].to=v;
head[u]=tot;
an[tot].l=l;
}
void dfs(int u,int fa)
{
size[u]=;
for(int i=head[u];i;i=an[i].n)
if(an[i].to!=fa)
{
int v=an[i].to;
dfs(v,u);
size[u]+=size[v];
for(int j=min(m,size[u]);j>=;--j)//
for(int k=;k<=min(j,size[v]);++k)
if(dp[v][k]!=-0x3f3f3f3f)
{
long long num=(long long)(k*(m-k)+(n-size[v]-(m-k))*(size[v]-k))*an[i].l;
dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]+num);
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<n;++i)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);add(b,a,c);
}
memset(dp,-0x3f,sizeof(dp));
for(int i=;i<=n;++i)
dp[i][]=dp[i][]=;//
dfs(,);
cout<<dp[][m];
return ;
}
这种写法太慢了,并没有做到严格n^2,bzoj会TLE,下面这种写法是稳过的。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 2009
using namespace std;
typedef long long ll;
ll dp[N][N],size[N],m,n,a,b,c,tot,head[N],g[N];
struct dsd
{
ll n,to,l;
}an[N<<];
inline void add(ll u,ll v,ll l)
{
an[++tot].n=head[u];
an[tot].to=v;
head[u]=tot;
an[tot].l=l;
}
ll mi(ll x,ll y){return x<y?x:y;}
ll ma(ll x,ll y){return x<y?y:x;}
void dfs(ll u,ll fa){
size[u]=;
for(ll i=head[u];i;i=an[i].n)
if(an[i].to!=fa){
ll v=an[i].to;
dfs(v,u);
ll x=mi(m,size[u]),y=mi(m,size[v]);
for(int j=;j<=m;++j)g[j]=;
for(ll j=x;j>=;--j)
for(int k=;k<=y;++k)if(j+k<=m){
ll gyx=((ll)k*(m-k)+(n-size[v]-(m-k))*(size[v]-k))*an[i].l;
g[j+k]=ma(g[j+k],dp[u][j]+dp[v][k]+gyx);
}
for(int j=;j<=m;++j)dp[u][j]=g[j];
size[u]+=size[v];
}
}
inline int rd(){
int x=;char c=getchar();
while(!isdigit(c))c=getchar();
while(isdigit(c)){
x=(x<<)+(x<<)+(c^);
c=getchar();
}
return x;
}
int main()
{
n=rd();m=rd();
for(int i=;i<n;++i){
a=rd();b=rd();c=rd();
add(a,b,c);add(b,a,c);
}
memset(dp,-0x3f,sizeof(dp));
for(int i=;i<=n;++i)
dp[i][]=dp[i][]=;
dfs(,);
printf("%lld",dp[][m]);
return ;
}
[HAOI2015]树上染色(树形背包)的更多相关文章
- 洛谷 P3177 [HAOI2015]树上染色 树形DP
洛谷 P3177 [HAOI2015]树上染色 树形DP 题目描述 有一棵点数为 \(n\) 的树,树边有边权.给你一个在 \(0 \sim n\)之内的正整数 \(k\) ,你要在这棵树中选择 \( ...
- bzoj 4033: [HAOI2015]树上染色 [树形DP]
4033: [HAOI2015]树上染色 我写的可是\(O(n^2)\)的树形背包! 注意j倒着枚举,而k要正着枚举,因为k可能从0开始,会使用自己更新一次 #include <iostream ...
- 【BZOJ4033】[HAOI2015]树上染色 树形DP
[BZOJ4033][HAOI2015]树上染色 Description 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染 ...
- [BZOJ4033][HAOI2015]树上染色(树形DP)
4033: [HAOI2015]树上染色 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2437 Solved: 1034[Submit][Stat ...
- bzoj4033 [HAOI2015]树上染色——树形DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4033 树形DP,状态中加入 x 与父亲之间的边的贡献: 边权竟然是long long... ...
- BZOJ 4033 [HAOI2015]树上染色 ——树形DP
可以去UOJ看出题人的题解. 这样的合并,每一个点对只在lca处被考虑到,复杂度$O(n^2)$ #include <map> #include <ctime> #includ ...
- BZOJ_4033_[HAOI2015]树上染色_树形DP
BZOJ_4033_[HAOI2015]树上染色_树形DP Description 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并 将其他的 ...
- BZOJ4033: [HAOI2015]树上染色(树形DP)
4033: [HAOI2015]树上染色 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 3461 Solved: 1473[Submit][Stat ...
- BZOJ4033 HAOI2015 树上染色 【树上背包】
BZOJ4033 HAOI2015 树上染色 Description 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染成白 ...
- BZOJ 4033[HAOI2015] 树上染色(树形DP)
4033: [HAOI2015]树上染色 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 3188 Solved: 1366[Submit][Stat ...
随机推荐
- mysql-SQL Error: 1205, SQLState: 41000
mysql-SQL Error: 1205, SQLState: 41000——CSDN问答频道https://ask.csdn.net/questions/176492 mysql-SQL Erro ...
- Thread类相关方法
线程对象 每一个线程都是和类Thread的实例相关联的.在Java中,有两种基本的使用Thread对象的方式,可用来创建并发性程序. 1.在应用程序需要发起异步任务的时候,只要生成一个Thread对 ...
- [转帖]ipvsadm命令参考及其应用例子
ipvsadm命令参考及其应用例子 https://blog.csdn.net/orichisonic/article/details/47375227 只是简单创建了 service和添加serve ...
- 爱上linux 简单实现移动办公处理环境.
1. 这周一直在鼓捣linux上面的环境测试. 简单的将 我们的产品部署到了linux上面 详情见前面的 blog 2. 有时候下班了 或者是 在WC (科技园wc排队 说多了都是泪) 或者是眼睛不舒 ...
- easyui 自动动态合并单元格
.......onLoadSuccess : function(data) { if (data.rows.length > 0) { //调用mergeCellsByField()合并单元格 ...
- Python学习之路—————day04
今日内容: 1. 循环语句 1.1 if判断 1.2 while循环 1.3 for循环 一.if判断 语法一: if 条件 代码块1 代码块2 代码块3 # 例: sex='female' age= ...
- Hibernate最佳实战
1:一对一,一对多,多对多双向管理必设mappedBy ,将关系交给乙方维护,不然的话会在双方都建立关系,比如一对一双向的时候双方都会保存对方的id外键管理 具体在项目中采用双向还是单项看实际情况. ...
- BZOJ1324Exca王者之剑&BZOJ1475方格取数——二分图最大独立集
题目描述 输入 第一行给出数字N,M代表行列数.N,M均小于等于100 下面N行M列用于描述数字矩阵 输出 输出最多可以拿到多少块宝石 样例输入 2 2 1 2 2 1 样例输出 4 题意就是 ...
- BZOJ1565[NOI2009]植物大战僵尸——最大权闭合子图+拓扑排序
题目描述 Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏.Plants(植物)和Zombies(僵尸)是游戏的主角,其中Plants防守,而Zombies进攻.该款游戏包含多 ...
- Number Sequence POJ - 1019 递推 数学
题意 1 12 123 1234 12345 ....这样的序列 问第n位数字是几 是数字! 1-9! 思路:递推关系 主要是位数的计算 用a[i]=a[i-1]+(int)log10((do ...