[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