分类
标签
2-SAT AC自动机 BFS CDQ dfs DP fail树 FFT FFT&NTT FWT hash KD-Tree KMP LCA SPFA STL Tarjan Treap Trie 主席树 乱搞 二分 二分图匹配 二分答案 二维SPFA 交互 位运算 其他 最小生成树 分块 区间DP 半平面交 博弈论 可持久化 可持久化Trie树 后缀数组 图库 平衡树 并查集 插头DP 数学 数论 无旋Treap 日记 暴力 权值树状数组 栈 树DP 树套树 树状数组 树贪心 概率DP 模拟 欧拉定理 点分治 状压DP 生成函数 矩阵乘 线性规划 线段树 组合 网络流 群论 莫比乌斯反演 计算几何 贪心 费用流 高斯消元
603 字
3 分钟
BZOJ 2097 [Usaco2010 Dec]Exercise 奶牛健美操 题解 二分答案 树贪心 dfs
Description
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
Sample Output
2
题解
二分答案 贪心验证
每次dfs时将子节点到他的dis记录一直删边直到小于mid
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int son[100005],mid;
struct edge{
int END,next;
}v[200005];
int first[100005],p,f[100005],q[100005],tot;
void add(int a,int b){
v[p].END=b;v[p].next=first[a];first[a]=p++;
v[p].END=a;v[p].next=first[b];first[b]=p++;
}
int cmp(const int a,const int b){
return b<a;
}
void dfs(int rt,int fa){
f[rt]=0;
for(int i=first[rt];i!=-1;i=v[i].next)
if(v[i].END!=fa) dfs(v[i].END,rt);
int cnt=0;q[0]=0;
for(int i=first[rt];i!=-1;i=v[i].next)
if(v[i].END!=fa) q[++cnt]=f[v[i].END]+1;
sort(q+1,q+cnt+1,cmp);
if(!cnt) return;
if(cnt==1){
if(q[1]>mid){
tot++;
return;
}
else {f[rt]=q[1];return;}
}
int i=2;
while(q[i-1]+q[i]>mid&&i<=cnt){
tot++;
i++;
}
if(i==cnt+1&&q[i-1]>mid)tot++;
f[rt]=q[i-1];
}
int main()
{
memset(first,-1,sizeof(first));
int n,m;
scanf("%d%d",&n,&m);
int a,b;
for(int i=1;i<n;i++){
scanf("%d%d",&a,&b);
add(a,b);
}
//int ans=0;
int l=1,r=n;
while(l<r){
mid=l+r>>1;tot=0;
dfs(1,0);
if(tot<=m)r=mid;
else l=mid+1;
}
printf("%d",l);
//while(1);
}
BZOJ 2097 [Usaco2010 Dec]Exercise 奶牛健美操 题解 二分答案 树贪心 dfs
https://www.nekomio.com/posts/16/