zoukankan      html  css  js  c++  java
  • bzoj 2067: [Poi2004]SZN【贪心+二分+树形dp】

    第一问就是Σ(deg[u]-1)/2+1
    第二问是二分,判断的时候考虑第一问的贪心规则,对于奇度数的点,两两配对之后一条延伸到上面;对于欧度数的点,两两配对或者deg[u]-2的点配对,然后一条断在这个点,一条延伸上去,按这个树形dp判断一下即可

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=10005;
    int n,h[N],cnt,ans=1,d[N],f[N],fl,a[N],tot;
    struct qwe
    {
    	int ne,to;
    }e[N<<1];
    int read()
    {
    	int r=0,f=1;
    	char p=getchar();
    	while(p>'9'||p<'0')
    	{
    		if(p=='-')
    			f=-1;
    		p=getchar();
    	}
    	while(p>='0'&&p<='9')
    	{
    		r=r*10+p-48;
    		p=getchar();
    	}
    	return r*f;
    }
    void add(int u,int v)
    {
    	cnt++;
    	e[cnt].ne=h[u];
    	e[cnt].to=v;
    	d[v]++;
    	h[u]=cnt;
    }
    bool pd(int mid,int w)
    {
    	int l=1,r=tot;
    	while(l<r)
    	{
    		if(l==mid)
    			l++;
    		if(r==mid)
    			r--;
    		if(a[l]+a[r]>w)
    			return 0;
    		l++,r--;
    	}
    	return 1;
    }
    void dfs(int u,int fa,int w)
    {
    	if(!fl)
    		return;
    	for(int i=h[u];i;i=e[i].ne)
    		if(e[i].to!=fa)
    			dfs(e[i].to,u,w);
    	f[u]=0,tot=0;
    	for(int i=h[u];i;i=e[i].ne)
    		if(e[i].to!=fa)
    			a[++tot]=f[e[i].to]+1;
    	sort(a+1,a+1+tot);
    	if(!tot)
    		return;
    	if(a[tot]>w)
    	{
    		fl=0;
    		return;
    	}
    	if(!(tot&1))
    	{
    		for(int i=1;i<=tot/2;i++)
    			if(a[i]+a[tot-i+1]>w)
    			{
    				if(u==1)
    				{
    					fl=0;
    					return;
    				}
    				else
    				{
    					tot--;
    					break;
    				}
    			}
    	}
    	if(tot&1)
    	{
    		int l=1,r=tot,ans=tot+1;
    		while(l<=r)
    		{
    			int mid=(l+r)>>1;
    			if(pd(mid,w))
    				r=mid-1,ans=mid;
    			else
    				l=mid+1;
    		}
    		if(ans>tot)
    		{
    			fl=0;
    			return;
    		}
    		else
    			f[u]=a[ans];
    	}
    }
    bool ok(int w)
    {
    	fl=1;
    	dfs(1,0,w);
    	return fl;
    }
    int main()
    {
    	n=read();
    	for(int i=1;i<n;i++)
    	{
    		int x=read(),y=read();
    		add(x,y),add(y,x);
    	}
    	for(int i=1;i<=n;i++)
    		ans+=(d[i]-1)>>1;
    	int l=1,r=n,len=1;
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(ok(mid))
    			r=mid-1,len=mid;
    		else
    			l=mid+1;
    	}
    	printf("%d %d
    ",ans,len);
    	return 0;
    }
    
  • 相关阅读:
    VM439:1 https://unidemo.dcloud.net.cn 不在以下 request 合法域名列表中,请参考
    vue点击出现蒙版
    vue实现轮播图
    js函数调用的几种方法
    js中的object类型
    vue报错笔记
    vue中项目如何引入sass (vue-cli项目)
    vue编写轮播图组件
    VSCode配置 Debugger for Chrome插件
    就是一段程序,可以求出N个不等长列表中取N个元素形成的所有组合
  • 原文地址:https://www.cnblogs.com/lokiii/p/9783997.html
Copyright © 2011-2022 走看看