[Usaco2010 Dec]Exercise 奶牛健美操

Posted Forever_goodboy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Usaco2010 Dec]Exercise 奶牛健美操相关的知识,希望对你有一定的参考价值。

 [Usaco2010 Dec]Exercise 奶牛健美操

时间限制: 1 Sec  内存限制: 64 MB

题目描述

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,即是最优答案(当然不是唯一的)。

输入

* 第1行: 两个空格分隔的整数V和S * 第2...V行: 两个空格分隔的整数A_i和B_i

输出

* 第1行:一个整数,表示FJ可以获得的最大的直径。

样例输入

7 2
6 7
3 4
6 5
1 2
3 2
4 5

样例输出

2
solution:
    最大值最小一看就二分,但注意用一下大根堆,只要有边权值大于当前二分的答案,++now,如果now>s,return false;
如果最大值和次大值相加大于二分的答案,++now,不过二分的右边界需要设置成v/s,否则会T一个点。
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <queue>
  6 using namespace std;
  7 #define root 1
  8 int read() {
  9     int s=0,f=1;
 10     char ch=getchar();
 11     for( ; ch<0||ch>9; f=(ch==-)?(-1):f,ch=getchar()) ;
 12     for( ; ch>=0&&ch<=9; s=(s<<1)+(s<<3)+(ch^48),ch=getchar()) ;
 13     return s*f;
 14 }
 15 int now,v,s,tot,r[100005],deep[100005],siz[100005];
 16 int fir_dep[100005],sec_dep[100005];
 17 struct edge {
 18     int to,next;
 19 } c[200005];
 20 void add(int x,int y) {
 21     c[tot]=(edge) {
 22         y,r[x]
 23     };
 24     r[x]=tot++;
 25 }
 26 int dfs1(int u,int v) {
 27     siz[u]=1;
 28     fir_dep[u]=sec_dep[u]=deep[u]=deep[v]+1;
 29     for(int i=r[u]; ~i; i=c[i].next) {
 30         if(c[i].to!=v) {
 31             deep[c[i].to]=deep[u]+1;
 32             int dep=dfs1(c[i].to,u);
 33             if(dep>fir_dep[u]) {
 34                 sec_dep[u]=fir_dep[u];
 35                 fir_dep[u]=dep;
 36             }
 37             siz[u]+=siz[c[i].to];
 38         }
 39     }
 40     return fir_dep[u];
 41 }
 42 priority_queue <int> q[100005];
 43 bool dfs(int len,int u,int v) {
 44     if(siz[u]==1) {
 45         q[v].push(1);
 46         return true;
 47     }
 48     while(!q[u].empty()) {
 49         q[u].pop();
 50     }
 51     q[u].push(0);
 52     for(int i=r[u]; ~i; i=c[i].next) {
 53         if(c[i].to!=v) {
 54             bool pd=dfs(len,c[i].to,u);
 55             if(!pd) {
 56                 return false;
 57             }
 58         }
 59     }
 60     while(!q[u].empty()&&q[u].top()!=0) {
 61         int num=q[u].top();
 62         q[u].pop();
 63         if(num>len) {
 64             ++now;
 65             if(now>s) {
 66                 return false;
 67             }
 68             continue;
 69         }
 70         if(num+q[u].top()>len) {
 71             ++now;
 72             if(now>s) {
 73                 return false;
 74             }
 75         } else {
 76             q[u].push(num);
 77             break;
 78         }
 79     }
 80     q[v].push(q[u].top()+1);
 81     return true;
 82 }
 83 int main() {
 84     memset(r,0xff,sizeof(r));
 85     v=read(),s=read();
 86     for(int x,y,i=1; i<v; ++i) {
 87         x=read(),y=read();
 88         add(x,y),add(y,x);
 89     }
 90     dfs1(root,0);
 91     int l=1,r=v/s+1;
 92     while(l<r) {
 93         int mid=(l+r)>>1;
 94         now=0;
 95         bool dd=dfs(mid,root,0);
 96         if(now>s) {
 97             l=mid+1;
 98         } else {
 99             r=mid;
100         }
101     }
102     printf("%d",l);
103     return 0;
104 }

 

 

以上是关于[Usaco2010 Dec]Exercise 奶牛健美操的主要内容,如果未能解决你的问题,请参考以下文章

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

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

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

BZOJ 1717 Usaco 2006 Dec 产奶模式

BZOJ 2100 Usaco2010 Dec Apple Delivery

BZOJ——2101: [Usaco2010 Dec]Treasure Chest 藏宝箱