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

    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(0);
     8     char ch(getchar());
     9     for(;ch<'0'||ch>'9';ch=getchar());
    10     for(;ch>='0'&&ch<='9';sum=sum*10+(ch^48),ch=getchar());
    11     return sum;
    12 }
    13 struct edge{
    14     int e;
    15     edge *n;
    16 }a[200005],*pre[100005];
    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[100005],fa[100005];
    25 int ans;
    26 int mid,num;
    27 int tmp[100005];
    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[0]=0;
    44     f[u]=0;
    45     for(edge *i=pre[u];i;i=i->n){
    46         int e(i->e);
    47         if(e!=fa[u])
    48             tmp[++tmp[0]]=f[e]+1;
    49     }
    50     int size(tmp[0]);
    51     sort(tmp+1,tmp+1+size,cmp);
    52     tmp[size+1]=0;
    53     for(int i=1;i<=size;++i){
    54         if(tmp[i]+tmp[i+1]>mid)
    55             ++num;
    56         else{
    57             f[u]=tmp[i];
    58             break;
    59         }
    60     }
    61 }
    62 inline bool check(){
    63     num=0;
    64     memset(f,0,sizeof(f));
    65     dfs(1);
    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)>>1;
    73         if(check())
    74             r=mid-1,ans=mid;
    75         else
    76             l=mid+1;
    77     }
    78 }
    79 int main(){
    80     memset(pre,NULL,sizeof(pre));
    81     n=read(),m=read();
    82     for(int i=1;i<n;++i){
    83         int x(read()),y(read());
    84         insert(x,y),insert(y,x);
    85     }
    86     ef(1,n);
    87     printf("%d",ans);
    88 }
    View Code
  • 相关阅读:
    微信小程序配置域名的时候提示“校验文件验证失败”
    微信小程序封装mixins方法
    nuxt中报window is not defined
    nuxt中iview按需加载配置
    nuxt 项目安装及环境配置
    使用指针遍历图像
    图像添加噪声(椒盐噪声)
    Java中基本知识梳理【定时器实现多线程】-----2015年3月15日
    Java基础知识---【静态成员,封装性,包】------2015年3月6日
    Java中基本知识梳理【基本变量的处理】-----2015年3月6日
  • 原文地址:https://www.cnblogs.com/hzoi-mafia/p/7512339.html
Copyright © 2011-2022 走看看