[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])$是不可行的,因为这不保证合法,但我们想,当我们选出两条儿子所在的直链,发现当他们接在一起时长度过大,需要从中砍断的时候,会有这样的事情:

  1. 砍较长链链顶的边最优
  2. 砍完该边后,该链不再对父节点造成影响

第二点显然,砍完之后该链与父节点不再属于同一联通块内,故不会再影响

第一点也很显然(废话),如果我们砍较短链,或者不是链顶的边,那么最长直链可能还会与其他直链相接再次产生不合法链,需要多砍一次,所以砍较长链链顶的边是最优的

那么我们就可以处理了,将当前节点的所有$f[son]$从大到小排序,依次枚举,判断相邻的两条直链长度相接是否合法,假如合法,将$f[i]$赋值,否则继续枚举,并且记录砍掉的边的数目$++$

注意处理某些奇怪的边界问题

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<cstdio>
  5. using namespace std;
  6. inline int read(){
  7. int sum();
  8. char ch(getchar());
  9. for(;ch<''||ch>'';ch=getchar());
  10. for(;ch>=''&&ch<='';sum=sum*+(ch^),ch=getchar());
  11. return sum;
  12. }
  13. struct edge{
  14. int e;
  15. edge *n;
  16. }a[],*pre[];
  17. int tot;
  18. inline void insert(int s,int e){
  19. a[++tot].e=e;
  20. a[tot].n=pre[s];
  21. pre[s]=&a[tot];
  22. }
  23. int n,m;
  24. int f[],fa[];
  25. int ans;
  26. int mid,num;
  27. int tmp[];
  28. inline bool cmp(int x,int y){
  29. return x>y;
  30. }
  31. inline void dfs(int u){
  32. bool flag(false);
  33. for(edge *i=pre[u];i;i=i->n){
  34. int e(i->e);
  35. if(e!=fa[u]){
  36. flag=true;
  37. fa[e]=u;
  38. dfs(e);
  39. }
  40. }
  41. if(!flag)
  42. return;
  43. tmp[]=;
  44. f[u]=;
  45. for(edge *i=pre[u];i;i=i->n){
  46. int e(i->e);
  47. if(e!=fa[u])
  48. tmp[++tmp[]]=f[e]+;
  49. }
  50. int size(tmp[]);
  51. sort(tmp+,tmp++size,cmp);
  52. tmp[size+]=;
  53. for(int i=;i<=size;++i){
  54. if(tmp[i]+tmp[i+]>mid)
  55. ++num;
  56. else{
  57. f[u]=tmp[i];
  58. break;
  59. }
  60. }
  61. }
  62. inline bool check(){
  63. num=;
  64. memset(f,,sizeof(f));
  65. dfs();
  66. if(num<=m)
  67. return true;
  68. return false;
  69. }
  70. inline void ef(int l,int r){
  71. while(l<=r){
  72. mid=(l+r)>>;
  73. if(check())
  74. r=mid-,ans=mid;
  75. else
  76. l=mid+;
  77. }
  78. }
  79. int main(){
  80. memset(pre,NULL,sizeof(pre));
  81. n=read(),m=read();
  82. for(int i=;i<n;++i){
  83. int x(read()),y(read());
  84. insert(x,y),insert(y,x);
  85. }
  86. ef(,n);
  87. printf("%d",ans);
  88. }

[Usaco2010 Dec]Exercise 奶牛健美操的更多相关文章

  1. BZOJ_2097_[Usaco2010 Dec]Exercise 奶牛健美操_二分答案+树形DP

    BZOJ_2097_[Usaco2010 Dec]Exercise 奶牛健美操_二分答案+树形DP Description Farmer John为了保持奶牛们的健康,让可怜的奶牛们不停在牧场之间 的 ...

  2. [bzoj2097][Usaco2010 Dec]Exercise 奶牛健美操_贪心_树形dp_二分

    Exercise bzoj-2097 Usaco-2010 Dec 题目大意:题目链接 注释:略. 想法:题目描述生怕你不知道这题在考二分. 关键是怎么验证?我们想到贪心的删边. 这样的策略是显然正确 ...

  3. 【bzoj2097】[Usaco2010 Dec]Exercise 奶牛健美操 二分+贪心

    题目描述 Farmer John为了保持奶牛们的健康,让可怜的奶牛们不停在牧场之间 的小路上奔跑.这些奶牛的路径集合可以被表示成一个点集和一些连接 两个顶点的双向路,使得每对点之间恰好有一条简单路径. ...

  4. BZOJ——T 2097: [Usaco2010 Dec]Exercise 奶牛健美操

    http://www.lydsy.com/JudgeOnline/problem.php?id=2097 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit:  ...

  5. BZOJ2097: [Usaco2010 Dec]Exercise 奶牛健美操 贪心+伪树dp+二分

    //论全局变量的杀伤力....QAQ#include<cstdio> #include<iostream> #include<cstdlib> #include&l ...

  6. BZOJ2097: [Usaco2010 Dec]Exercise 奶牛健美操

    n<=100000的树,砍S<n条边,求砍完后S+1棵树的最大直径的最小值. 树的直径要小小哒,那考虑一棵子树的情况吧!一棵子树的直径,就是子树根节点各儿子的最大深度+次大深度.就下面这样 ...

  7. bzoj 2097: [Usaco2010 Dec]Exercise 奶牛健美操【二分+树形dp】

    二分答案,然后dp判断是否合法 具体方法是设f[u]为u点到其子树中的最长链,每次把所有儿子的f值取出来排序,如果某两条能组合出大于mid的链就断掉f较大的一条 a是全局数组!!所以要先dfs完子树才 ...

  8. BZOJ 2097 [Usaco2010 Dec]Exercise 奶牛健美操

    [题意] 给出一棵树.现在可以在树中删去m条边,使它变成m+1棵树.要求最小化树的直径的最大值. [题解] 二分答案.$Check$的时候用$DP$,记录当前节点每个儿子的直径$v[i]$,如果$v[ ...

  9. BZOJ 2097: [Usaco2010 Dec]Exercise 奶牛健美操 二分 + 贪心 + 树上问题

    Code: #include<bits/stdc++.h> using namespace std; #define setIO(s) freopen(s".in",& ...

随机推荐

  1. 确定比赛名次(toposort)

    http://acm.hdu.edu.cn/showproblem.php?pid=1285 #include <stdio.h> #include <string.h> ; ...

  2. Gym - 101972B Arabella Collegiate Programming Contest (2018) B. Updating the Tree 树DFS

    题面 题意:T组数据,每次给你1e5个点的树(1为根),每个点有一权值,询问1-n每个节点的子树中, 至少修改几个点的权值(每次都可以任意修改),才能让子树中任意2点的距离==他们权值差的绝对值 无解 ...

  3. null, undefined,"",0,false是什么关系?

    null本质上和0,"",false是一类东西,它们都表示一种数据类型的非值.正如0表示数字类型的非值,""表示字符类型的非值一样,null表示完全空的对象,即 ...

  4. [Swift通天遁地]七、数据与安全-(20)快速实现MD5/Poly1305/Aes/BlowFish/Chacha/Rabbit

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  5. php从数据库读取中文显示问号??的解决办法

    出错原因:1.数据库编码格式不对 2.PHP编码格式不对 3.浏览器编码格式不对 上面三者编码格式不统一,就会出现问题 数据库读取的时候在mysqli_connect()之后要设置连接字符编码mysq ...

  6. 巴什博弈----hdu2147-----较难

    kiki's game Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 40000/10000 K (Java/Others)Total ...

  7. 【POJ3255/洛谷2865】[Usaco2006 Nov]路障Roadblocks(次短路)

    题目: POJ3255 洛谷2865 分析: 这道题第一眼看上去有点懵-- 不过既然要求次短路,那估计跟最短路有点关系,所以就拿着优先队列优化的Dijkstra乱搞,搞着搞着就通了. 开两个数组:\( ...

  8. 【Leetcode 220】 Contains Duplicate III

    问题描述:判断数组中是否存在<ai aj> abs(ai - aj)<=t  && abs(i - j) <=k: 问题分析:需要一个数据结构来维护满足条件k. ...

  9. C# asp.net repeater实现排序功能,自动排序,点击头部排序,点击列排序

    在网上看到好多关于repeater排序的,自己动手用了,发现一些问题,贴源码后把发现的问题以及解决方法给出 repeater实现排序功能(单击升序排列,再单击降序排列).原理很简单,在<TD&g ...

  10. 函数 out 传值 分割

    public void Jia(int a ,int b) { a = a + b; Console.WriteLine(a); } public void Jia1(int a,out int b) ...