首页 > 其他 > 详细

【二分】

时间:2019-09-29 19:52:37      阅读:74      评论:0      收藏:0      [点我收藏+]

神奇的check函数,

任世界千变万化,我check永远是check

 

1>land

一棵树,求砍cut刀以后,
cut+1棵数中,直径最大值 最小是多少

//因为cut刀怎么砍与直径最大值有关,不好控制,
//所以我们通过枚举最大的直径,然后去dfs砍枝

//然后,让我们来见证,这个神奇的二分剪法 
#include<cstdio>
#include<cstdlib>
#include<vector>
using namespace std;
int n,cut;
const int N=4e5+3;
int d[N],sz[N];
vector <int> g[N];

int mid,sum;
int check(int nw,int f)
{
    int l_mn=mid,r_mx=0,cnt=0; 
    
    for(int i=0;i<sz[nw];i++)
    {
        int u=g[nw][i];
        if(u==f) continue;
        
        int len=check(u,nw)+1;
        if(len>mid) sum++;
        else if(len>(mid>>1)) cnt++,l_mn=min(l_mn,len);
        else if(len>0) r_mx=max(r_mx,len);
    }
    
    if(cnt)
    {
        sum+=cnt;
        if(l_mn+r_mx<=mid)
        {
            sum--;
            return l_mn;
        }
    }
    return r_mx;
}

int main()
{
    scanf("%d%d",&n,&cut);
    int u,v;
    for(int i=1;i<n;i++)
        scanf("%d%d",&u,&v),g[u].push_back(v),g[v].push_back(u);
    for(int i=1;i<=n;i++)
        sz[i]=g[i].size() ;
    
    if(cut+1>=n) 
        printf("0\n");
    else
    {
        int l=0,r=n,ans=0;
        while(l<=r)
        {
            mid=(l+r)>>1;//>cut就是这个解太优了,要把解变差一点,就是把ans的范围往右边调整 
            sum=0,check(1,0); 
if(sum>cut) l=mid+1; else ans=mid,r=mid-1;//重点注意这个地方的写法!!!! . //求的是cut刀,最小ans是多少, //但是有可能此最小ans的时候,最小砍cut-1刀, //所以写的时候,就是<=cut的时候,都更新答案,但是大于不行 } printf("%d\n",ans); } return 0; }

2>派

 

3>皇帝的烦恼

 

【二分】

原文:https://www.cnblogs.com/xwww666666/p/11609217.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!