[BZOJ2097][Usaco2010 Dec]Exercise 奶牛健美操(二分+树形dp+贪心)

44 篇文章 0 订阅
19 篇文章 0 订阅

题目:

我是超链接

题解:

奶牛题全是权限题?
最大值最小——二分嘛
还是要好好理解树的直径这道题目。。。然后灵活变通,这样你就可以知道这道题的方法
把找树的直径的过程“放慢拉长”,贪心的从子树开始截取已经要长出去的片段
长出去的片段一定要截取最大的啊(贪心一点嘛,小的更有发展空间啊

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define N 100005
using namespace std;
int tot,nxt[N*2],point[N],v[N*2],cnt,f[N],a[N];//f[x]表示x点到子树的最长链的距离
int cmp(int a,int b){return a>b;}
void addline(int x,int y)
{
    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
    ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void dfs(int x,int fa,int limit)
{
    f[x]=0;//每次都memset不觉得太慢了嘛
    bool fff=false;
    for (int i=point[x];i;i=nxt[i])
      if (v[i]!=fa)
      {
        dfs(v[i],x,limit);
        fff=true;
        f[x]=max(f[x],f[v[i]]+1);
      }
    if (!fff) return;//f[x]的完善完成
    a[0]=0;
    for (int i=point[x];i;i=nxt[i])
      if (v[i]!=fa) a[++a[0]]=f[v[i]]+1;//每条链长
    sort(a+1,a+a[0]+1,cmp); 
    for (int i=1;i<a[0];i++)
      if (a[i]+a[i+1]>limit) a[i]=0,cnt++;
    //从最大的开始,如果a[1]被t了,最大的组合就是a[2]+a[3],再考虑t不t a[2];如果a[1]没被t,啊呀最大的组合a[1]+a[2]都没事你们后面的肯定没事啊
    if (a[a[0]]>limit) a[a[0]]=0,cnt++;
    sort(a+1,a+a[0]+1,cmp);//很多都断开了(a[i]=0),要重排
    f[x]=a[1]; 
}
int check(int limit)
{
    cnt=0;
    dfs(1,0,limit);
    return cnt;
}
int main()
{
    int n,s,i;
    scanf("%d%d",&n,&s);
    for (i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        addline(x,y);
    }
    int l=1,r=n-1;
    while (l<=r)//直径的长度 
    {
        int mid=(l+r)>>1;
        if (check(mid)<=s) r=mid-1;
        else l=mid+1;
    }
    printf("%d",r+1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值