[Usaco2010 Dec]Exercise 奶牛健美操
[Usaco2010 Dec]Exercise 奶牛健美操
题目
Farmer John为了保持奶牛们的健康,让可怜的奶牛们不停在牧场之间 的小路上奔跑。这些奶牛的路径集合可以被表示成一个点集和一些连接 两个顶点的双向路,使得每对点之间恰好有一条简单路径。简单的说来, 这些点的布局就是一棵树,且每条边等长,都为1。 对于给定的一个奶牛路径集合,精明的奶牛们会计算出任意点对路径的最大值, 我们称之为这个路径集合的直径。如果直径太大,奶牛们就会拒绝锻炼。 Farmer John把每个点标记为1..V (2 <= V <= 100,000)。为了获得更加短 的直径,他可以选择封锁一些已经存在的道路,这样就可以得到更多的路径集合, 从而减小一些路径集合的直径。 我们从一棵树开始,FJ可以选择封锁S (1 <= S <= V-1)条双向路,从而获得 S+1个路径集合。你要做的是计算出最佳的封锁方案,使得他得到的所有路径集合 直径的最大值尽可能小。 Farmer John告诉你所有V-1条双向道路,每条表述为:顶点A_i (1 <= A_i <= V) 和 B_i (1 <= B_i <= V; A_i!= B_i)连接。 我们来看看如下的例子:线性的路径集合(7个顶点的树) 1---2---3---4---5---6---7 如果FJ可以封锁两条道路,他可能的选择如下: 1---2 | 3---4 | 5---6---7 这样最长的直径是2,即是最优答案(当然不是唯一的)。
INPUT
第1行: 两个空格分隔的整数V和S * 第2...V行: 两个空格分隔的整数A_i和B_i
OUTPUT
第1行:一个整数,表示FJ可以获得的最大的直径。
SAMPLE
INPUT
7 2
6 7
3 4
6 5
1 2
3 2
4 5
OUTPUT
2
解题报告
二分答案$+$贪心验证,竟然放在$DP$专题里= =(可能是我造化不够)
首先我们可以看到题面中闪闪发光的一句话
最大值尽可能小
这东西一眼看上去就知道,二分差不多就是可行的了
我们可以二分该最小值,然后验证其是否合法
我们设$f[i]$表示以第$i$个节点为根的子树中,合法的最长直链的长度
合法:
即保证最长链长度不可大于二分的答案
直链:
指链两端点路径不跨过根节点的链
然后我们就可以用$f[i]$计算要砍去多少条边,从而判断当前二分出的答案的合法性
那么问题来了,如何计算$f[i]$
显然直接求$max(f[son])$是不可行的,因为这不保证合法,但我们想,当我们选出两条儿子所在的直链,发现当他们接在一起时长度过大,需要从中砍断的时候,会有这样的事情:
- 砍较长链链顶的边最优
- 砍完该边后,该链不再对父节点造成影响
第二点显然,砍完之后该链与父节点不再属于同一联通块内,故不会再影响
第一点也很显然(废话),如果我们砍较短链,或者不是链顶的边,那么最长直链可能还会与其他直链相接再次产生不合法链,需要多砍一次,所以砍较长链链顶的边是最优的
那么我们就可以处理了,将当前节点的所有$f[son]$从大到小排序,依次枚举,判断相邻的两条直链长度相接是否合法,假如合法,将$f[i]$赋值,否则继续枚举,并且记录砍掉的边的数目$++$
注意处理某些奇怪的边界问题
- #include<algorithm>
- #include<iostream>
- #include<cstring>
- #include<cstdio>
- using namespace std;
- inline int read(){
- int sum();
- char ch(getchar());
- for(;ch<''||ch>'';ch=getchar());
- for(;ch>=''&&ch<='';sum=sum*+(ch^),ch=getchar());
- return sum;
- }
- struct edge{
- int e;
- edge *n;
- }a[],*pre[];
- int tot;
- inline void insert(int s,int e){
- a[++tot].e=e;
- a[tot].n=pre[s];
- pre[s]=&a[tot];
- }
- int n,m;
- int f[],fa[];
- int ans;
- int mid,num;
- int tmp[];
- inline bool cmp(int x,int y){
- return x>y;
- }
- inline void dfs(int u){
- bool flag(false);
- for(edge *i=pre[u];i;i=i->n){
- int e(i->e);
- if(e!=fa[u]){
- flag=true;
- fa[e]=u;
- dfs(e);
- }
- }
- if(!flag)
- return;
- tmp[]=;
- f[u]=;
- for(edge *i=pre[u];i;i=i->n){
- int e(i->e);
- if(e!=fa[u])
- tmp[++tmp[]]=f[e]+;
- }
- int size(tmp[]);
- sort(tmp+,tmp++size,cmp);
- tmp[size+]=;
- for(int i=;i<=size;++i){
- if(tmp[i]+tmp[i+]>mid)
- ++num;
- else{
- f[u]=tmp[i];
- break;
- }
- }
- }
- inline bool check(){
- num=;
- memset(f,,sizeof(f));
- dfs();
- if(num<=m)
- return true;
- return false;
- }
- inline void ef(int l,int r){
- while(l<=r){
- mid=(l+r)>>;
- if(check())
- r=mid-,ans=mid;
- else
- l=mid+;
- }
- }
- int main(){
- memset(pre,NULL,sizeof(pre));
- n=read(),m=read();
- for(int i=;i<n;++i){
- int x(read()),y(read());
- insert(x,y),insert(y,x);
- }
- ef(,n);
- printf("%d",ans);
- }
[Usaco2010 Dec]Exercise 奶牛健美操的更多相关文章
- BZOJ_2097_[Usaco2010 Dec]Exercise 奶牛健美操_二分答案+树形DP
BZOJ_2097_[Usaco2010 Dec]Exercise 奶牛健美操_二分答案+树形DP Description Farmer John为了保持奶牛们的健康,让可怜的奶牛们不停在牧场之间 的 ...
- [bzoj2097][Usaco2010 Dec]Exercise 奶牛健美操_贪心_树形dp_二分
Exercise bzoj-2097 Usaco-2010 Dec 题目大意:题目链接 注释:略. 想法:题目描述生怕你不知道这题在考二分. 关键是怎么验证?我们想到贪心的删边. 这样的策略是显然正确 ...
- 【bzoj2097】[Usaco2010 Dec]Exercise 奶牛健美操 二分+贪心
题目描述 Farmer John为了保持奶牛们的健康,让可怜的奶牛们不停在牧场之间 的小路上奔跑.这些奶牛的路径集合可以被表示成一个点集和一些连接 两个顶点的双向路,使得每对点之间恰好有一条简单路径. ...
- BZOJ——T 2097: [Usaco2010 Dec]Exercise 奶牛健美操
http://www.lydsy.com/JudgeOnline/problem.php?id=2097 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: ...
- BZOJ2097: [Usaco2010 Dec]Exercise 奶牛健美操 贪心+伪树dp+二分
//论全局变量的杀伤力....QAQ#include<cstdio> #include<iostream> #include<cstdlib> #include&l ...
- BZOJ2097: [Usaco2010 Dec]Exercise 奶牛健美操
n<=100000的树,砍S<n条边,求砍完后S+1棵树的最大直径的最小值. 树的直径要小小哒,那考虑一棵子树的情况吧!一棵子树的直径,就是子树根节点各儿子的最大深度+次大深度.就下面这样 ...
- bzoj 2097: [Usaco2010 Dec]Exercise 奶牛健美操【二分+树形dp】
二分答案,然后dp判断是否合法 具体方法是设f[u]为u点到其子树中的最长链,每次把所有儿子的f值取出来排序,如果某两条能组合出大于mid的链就断掉f较大的一条 a是全局数组!!所以要先dfs完子树才 ...
- BZOJ 2097 [Usaco2010 Dec]Exercise 奶牛健美操
[题意] 给出一棵树.现在可以在树中删去m条边,使它变成m+1棵树.要求最小化树的直径的最大值. [题解] 二分答案.$Check$的时候用$DP$,记录当前节点每个儿子的直径$v[i]$,如果$v[ ...
- BZOJ 2097: [Usaco2010 Dec]Exercise 奶牛健美操 二分 + 贪心 + 树上问题
Code: #include<bits/stdc++.h> using namespace std; #define setIO(s) freopen(s".in",& ...
随机推荐
- 确定比赛名次(toposort)
http://acm.hdu.edu.cn/showproblem.php?pid=1285 #include <stdio.h> #include <string.h> ; ...
- Gym - 101972B Arabella Collegiate Programming Contest (2018) B. Updating the Tree 树DFS
题面 题意:T组数据,每次给你1e5个点的树(1为根),每个点有一权值,询问1-n每个节点的子树中, 至少修改几个点的权值(每次都可以任意修改),才能让子树中任意2点的距离==他们权值差的绝对值 无解 ...
- null, undefined,"",0,false是什么关系?
null本质上和0,"",false是一类东西,它们都表示一种数据类型的非值.正如0表示数字类型的非值,""表示字符类型的非值一样,null表示完全空的对象,即 ...
- [Swift通天遁地]七、数据与安全-(20)快速实现MD5/Poly1305/Aes/BlowFish/Chacha/Rabbit
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
- php从数据库读取中文显示问号??的解决办法
出错原因:1.数据库编码格式不对 2.PHP编码格式不对 3.浏览器编码格式不对 上面三者编码格式不统一,就会出现问题 数据库读取的时候在mysqli_connect()之后要设置连接字符编码mysq ...
- 巴什博弈----hdu2147-----较难
kiki's game Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 40000/10000 K (Java/Others)Total ...
- 【POJ3255/洛谷2865】[Usaco2006 Nov]路障Roadblocks(次短路)
题目: POJ3255 洛谷2865 分析: 这道题第一眼看上去有点懵-- 不过既然要求次短路,那估计跟最短路有点关系,所以就拿着优先队列优化的Dijkstra乱搞,搞着搞着就通了. 开两个数组:\( ...
- 【Leetcode 220】 Contains Duplicate III
问题描述:判断数组中是否存在<ai aj> abs(ai - aj)<=t && abs(i - j) <=k: 问题分析:需要一个数据结构来维护满足条件k. ...
- C# asp.net repeater实现排序功能,自动排序,点击头部排序,点击列排序
在网上看到好多关于repeater排序的,自己动手用了,发现一些问题,贴源码后把发现的问题以及解决方法给出 repeater实现排序功能(单击升序排列,再单击降序排列).原理很简单,在<TD&g ...
- 函数 out 传值 分割
public void Jia(int a ,int b) { a = a + b; Console.WriteLine(a); } public void Jia1(int a,out int b) ...