bzoj 2067 [ Poi 2004 ] SZN —— 二分

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2067

问题1:贪心考虑,应该是每个点的儿子尽量两两配对,如果剩一个就和自己合并向上,所以 ans = 1 + ∑(1<= i <= n ) (deg[i] - 1)/2

问题2:二分最长线段的长度,设 f[x] 表示自己带着的链的长度(即儿子中剩下的那一个带来的长度),判断是否满足条件即可;

如果当前节点有偶数个儿子,那么加一个 f 值为0的,进行二分;

注意根要单独判断,因为不能向上带了。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid ((l+r)>>1)
using namespace std;
int const xn=10005;
int n,hd[xn],ct,to[xn<<1],nxt[xn<<1],f[xn],ans,deg[xn],a[xn],cnt;
void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;}
int rd()
{
    int ret=0,f=1; char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=0; ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘)ret=(ret<<3)+(ret<<1)+ch-‘0‘,ch=getchar();
    return f?ret:-ret;
}
bool ck2(int pos,int lim)
{
    for(int l=1,r=cnt;l<=r;l++,r--)
    {
        if(l==pos)l++;
        if(r==pos)r--;
        if(a[l]+a[r]>lim)return 0;
    }
    return 1;
}
bool ck(int x,int fa,int lim)
{
    for(int i=hd[x],u;i;i=nxt[i])
    {
        if((u=to[i])==fa)continue;
        if(!ck(u,x,lim))return 0;
    }
    cnt=0;
    for(int i=hd[x];i;i=nxt[i])if(to[i]!=fa)a[++cnt]=f[to[i]]+1;
    if(x==1)
    {
        sort(a+1,a+cnt+1);
        if(cnt%2)f[x]=a[cnt],cnt--;
        for(int l=1,r=cnt;l<=r;l++,r--)
            if(a[l]+a[r]>lim)return 0;
        return f[x]<=lim;
    }
    if(cnt%2==0)a[++cnt]=0;
    sort(a+1,a+cnt+1);
    int l=1,r=cnt,ret=-1;
    while(l<=r)
    {
        if(ck2(mid,lim))ret=mid,r=mid-1;
        else l=mid+1;
    }
    if(ret==-1)return 0;
    f[x]=a[ret];
    return f[x]<=lim;
}
int main()
{
    n=rd(); int ans1=1;
    for(int i=1,x,y;i<n;i++)
    {
        x=rd(); y=rd(); deg[x]++; deg[y]++;
        add(x,y); add(y,x);
    }
    for(int i=1;i<=n;i++)ans1+=(deg[i]-1)/2;
    printf("%d ",ans1);
    int l=0,r=n;
    while(l<=r)
    {
        if(ck(1,0,mid))ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/Zinn/p/9690653.html

时间: 2024-08-01 02:35:07

bzoj 2067 [ Poi 2004 ] SZN —— 二分的相关文章

BZOJ 1486 最小圈(二分+判负环)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1486 题意:给出一个有向图,边有权值.找到一个环,使得环上边的权值之和除以环上边的个数最小. 思路:二分答案x,每条边权值减去x,之后 找负环.从每个顶点开始DFS,记录到达某个顶点的距离,设当前DFS的顶点为u,距离dis[u].下一个顶点v, 权值w,则dis[u]+w<=0时才DFS(v).另外,若v是已经遍历过的,且dis[u]+w-dis[v](这个dis[v]是之前遍历时

bzoj 2067 [Poi2004]SZN——二分+贪心

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2067 最少的线段可以贪心地想出来.(结果还是写错了)就是偶数孩子可以自己配对,奇数孩子要带一个上去:算条数的时候在该条拐弯或截止的时候算,就是每个点的度数减1除以2求和,最后加上1表示根节点. 还以为第二问能贪心做呢.结果WA.奇数孩子带一个最小的上去是不行的:偶数孩子都不带上去也是不行的. 于是二分一下答案.结果WA.偶数孩子带一个尽量小的上去还能贪心,奇数孩子并不是用中间那个孩子与别的

BZOJ 1532 POI 2005 Kos-Dicing 最大流+二分

题目大意 给出一些比赛,每场比赛有一个人会胜出,问胜出最多次的人最少胜出多少次. 思路 首先二分答案,转化成判定问题.观察题目,注意到每场比赛只有一个人胜出,那么这可以成为网络流建图流量限制的依据. 具体: S->每个人 f:二分的最大胜出次数. 每个人->他参与的比赛 f:1 每场比赛->T f:1 每次判断最大流和比赛是否相等. CODE #define _CRT_SECURE_NO_WARNINGS #include <queue> #include <cstdi

[BZOJ 1082] [SCOI2005] 栅栏 【二分 + DFS验证(有效剪枝)】

题目链接:BZOJ - 1082 题目分析 二分 + DFS验证. 二分到一个 mid ,验证能否选 mid 个根木棍,显然要选最小的 mid 根. 使用 DFS 验证,因为贪心地想一下,要尽量先用提供的小的木木棍,尽量先做出需要的大的木棍,所以要先将提供的木棍和需要的木棍都排序. DFS 的时候是按照需要的木棍从大到小的顺序一层一层搜,每一层上是按照从小到大的顺序枚举提供的木棍.(当然枚举的时候已经不一定是从小到大了,有些木棍已经被截掉了一些.) 要使用两个有效的剪枝: 1)如果下一层的木棍和

[BZOJ 1207] [HNOI 2004] 打鼹鼠 【DP】

题目链接:BZOJ - 1207 题目分析 每一次打鼹鼠一定是从上一次打某只鼹鼠转移过来的,从打第 j 只鼹鼠能不能转移到打第 i 只鼹鼠,算一下曼哈顿距离和时间差就知道了. 那么就有一个 DP ,用 f[i] 表示打完第 i 只鼹鼠时最多打了多少只鼹鼠,然后 f[i] 可以由 f[1] .. f[i-1] 转移,类似于最长上升子序列. 然而这道题不能像最长上升子序列一样二分优化或树状数组优化,只能加一个判断 Maxf[] 都不够大就退出的优化.见代码. 代码 #include <iostrea

bzoj 2653 middle (主席树+二分)

版权声明:本文为博主原创文章,未经博主允许不得转载. bzoj 2653 题意: 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 其中a<b<c<d. 位置也从0开始标号. 强制在线. 解法: 首先可以想到的是二分答案,再判断是否满足条件 . 对于答案x,我们将原数组中大于等于x的数记1,小于的记为-1,

[BZOJ 1816] [Cqoi2010] 扑克牌 【二分答案】

题目链接:BZOJ - 1816 题目分析 答案具有可以二分的性质,所以可以二分答案. 验证一个答案 x 是否可行,就累加一下各种牌相对于 x 还缺少的量,如果总和超过了 x 或 m ,就不可行. 因为,当使用的joker小于等于 x 时,才可以通过合适地安排顺序使得每组牌中至多有一张 joker . 代码 #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio>

【BZOJ2067】[Poi2004]SZN 二分+树上贪心

[BZOJ2067][Poi2004]SZN Description String-Toys joint-stock 公司需要你帮他们解决一个问题. 他们想制造一个没有环的连通图模型. 每个图都是由一些顶点和特定数量的边构成. 每个顶点都可以连向许多的其他顶点.一个图是连通且无环的. 图是由许多的线做成的.一条线是一条连接图中两个顶点之间的路径.由于一些技术原因,两条线之间不能有重叠的部分,要保证图中任意一条边都被且仅被一条线所覆盖.由于一些技术原因,做一个这样的图的模型的费用取决于用了多少条线

BZOJ 1305 CQOI2009 dance跳舞 二分答案+最大流

题目大意:给定n个男生和n个女生,一些互相喜欢而一些不.举行几次舞会,每次舞会要配成n对.不能有同样的组合出现.每一个人仅仅能与不喜欢的人跳k次舞,求最多举行几次舞会 将一个人拆成两个点.点1向点2连一条流量为k的边.两个人若互相喜欢则点1之间连边,不喜欢则点2之间连边 对于每个要验证的x值 将每个人的点1向源或汇连一条流量为x的边 然后二分答案跑最大流就可以 #include<cstdio> #include<cstring> #include<iostream> #