正题

题目链接:https://www.luogu.com.cn/problem/AT4995


题目大意

\(n\)个点的一棵树,上面有一些棋子,每次可以选择两个棋子移动到他们之间的路径上相邻的点上,求最少多少步能移动到一个点上。

\(n\in[1,2000]\)


解题思路

如果固定最终节点的话,这个节点\(rt\)可行的话那么答案一定是\(\frac{\sum dis(rt,x)}{2}\)。

那么现在就转变为一个判定性问题,我们现在的操作变为了每次选择两个没有祖先关系的点,然后将它们往它们的\(LCA\)处移动一格。

同样的,我们发现如果我们在处理一个点\(x\)作为\(LCA\)时,我只会关心所有节点来自它的哪个儿子而不用考虑具体的位置。所以可以搞树形\(dp\)。

设\(f_x\)表示\(x\)的子树内最多的移动次数,定义\(s_x=\sum_{y\in subtree(x)}dis(x,y)\)的话,那么我们的转移和\(max\{s_y\}(x->y)\)有关。

若\(max\{s_y\}\times 2\leq s_x\),那么这里面的节点可以两两配对,\(f_x=\frac{s_x}{2}\)。

否则他\(s\)最大的子树\(y\)之中会有剩余的节点无法相互匹配,那么有$$f_x=s_x-s_y+min{f_y,s_y-\lfloor\frac{s_x}{2}\rfloor}$$

然后如果\(f_x=\frac{s_x}{2}\)那么\(x\)就是可行的答案

时间复杂度\(O(n^2)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2100;
struct node{
int to,next;
}a[N<<1];
int n,tot,ls[N],s[N],w[N],f[N],ans;
char v[N];
void addl(int x,int y){
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;return;
}
void dp(int x,int fa){
s[x]=w[x]=0;
int mx=0,son=0;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(y==fa)continue;
dp(y,x);w[x]+=w[y];
s[x]+=s[y]+w[y];
if(s[y]+w[y]>mx)
mx=s[y]+w[y],son=y;
}
if(mx*2>s[x])
f[x]=s[x]-mx+min(f[son],mx-s[x]/2);
else f[x]=s[x]/2;
w[x]+=(v[x]=='1');
return;
}
int main()
{
scanf("%d",&n);
scanf("%s",v+1);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
addl(x,y);addl(y,x);
}
ans=1e9;
for(int i=1;i<=n;i++){
dp(i,i);
if(s[i]&1)continue;
if(f[i]==s[i]/2)
ans=min(ans,f[i]);
}
if(ans==1e9)puts("-1");
else printf("%d\n",ans);
return 0;
}

AT4995-[AGC034E] Complete Compress【树形dp】的更多相关文章

  1. @atcoder - AGC034E@ Complete Compress

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个 N 个点的树,编号为 1, 2, ..., N.第 i ...

  2. 「AGC034E」 Complete Compress

    「AGC034E」 Complete Compress 显然可以枚举根. 然后把某两棵棋子同时往深度浅的方向提,即对不存在祖先关系的两个棋子进行操作. 如果能到达那么就更新答案. 问题转化为如何判定能 ...

  3. poj3417 LCA + 树形dp

    Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4478   Accepted: 1292 Descripti ...

  4. COGS 2532. [HZOI 2016]树之美 树形dp

    可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...

  5. 【BZOJ-4726】Sabota? 树形DP

    4726: [POI2017]Sabota? Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 128  Solved ...

  6. 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)

    题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...

  7. 树形DP

    切题ing!!!!! HDU  2196 Anniversary party 经典树形DP,以前写的太搓了,终于学会简单写法了.... #include <iostream> #inclu ...

  8. BZOJ 2286 消耗战 (虚树+树形DP)

    给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...

  9. POJ2342 树形dp

    原题:http://poj.org/problem?id=2342 树形dp入门题. 我们让dp[i][0]表示第i个人不去,dp[i][1]表示第i个人去 ,根据题意我们可以很容易的得到如下递推公式 ...

随机推荐

  1. C# 如何在编译时将 dll 复制到 bin\Release 目录下

    下面假设 Project 名为 Gamma4RTD,需要调用的 dll 文件为 rtddll.dll.IDE 是 Visual Studio 2015 打开 Visual Studio 2015 -& ...

  2. C++ 中的信号的处理

    C++ 信号处理 信号是由操作系统传给进程的中断,会提早终止一个程序.在 UNIX.LINUX.Mac OS X 或 Windows 系统上,可以通过按 Ctrl+C 产生中断. 有些信号不能被程序捕 ...

  3. Navicate 连接阿里云MySQL(两种方式及原理讲解)

    Navicate 连接阿里云(两种方式及原理讲解) 一.直连方式(通过3306端口) 1.概述 2. 环境准备 3.操作及讲解 二.使用SSH通道 1.概述 2.环境准备 3.操作及讲解 如果对你有帮 ...

  4. CPF 入门教程 - 各个控件介绍(八)

    CPF C#跨平台桌面UI框架 系列教程 CPF 入门教程(一) CPF 入门教程 - 数据绑定和命令绑定(二) CPF 入门教程 - 样式和动画(三) CPF 入门教程 - 绘图(四) CPF 入门 ...

  5. 【C语言】第4章 选择结构程序设计

    第4章 选择结构程序设计 C语言有两种选择语句: if 语句,实现两个分支的选择结构 switch 语句,实现多分支的选择结构 输入3个数a,b,c,要求按由小到大的顺序输出. 可以先用伪代码写出算法 ...

  6. python 截屏操作

    方法1: 用pyscreenshot,https://pypi.org/project/pyscreenshot/ 方法2:用autopy,https://pypi.org/project/autop ...

  7. 测试Kaggle kernel commit 是否会删除以前的output

    在kaggle上创建kernel,加入如下代码. 连续运行两次,可以看到保存的文件名字不一样,且无论运行错少次,都只有一个输出文件. 这说明,kaggle上的kernel每次commit运行,都会清空 ...

  8. struts框架返回json数据

    设置返回result类型为json格式 <package name="cn.konngo.action" namespace="/" extends=&q ...

  9. git01_常用命令

    git与github介绍 Git是什么 Git是一个开源的[分布式][版本控制系统],用于敏捷高效地处理任何或小或大的项目 版本控制器 CVS/SVN/Git SVN 客户端/服务器 GIT 客户端/ ...

  10. Docker容器管理——Docker容器常用命令

    1.查看所有的容器 docker ps 2.查看运行的容器 docker ps -a 3.启动.停止.重启docker容器 docker start ... docker stop ... docke ...