• 【HAOI2007】覆盖问题


    某人在山上种了N棵小树苗
    冬天来了,温度急速下降,小树苗脆弱得不堪一击,于是树主人想用一些塑料薄膜把这些小树遮盖起来
    经过一番长久的思考,他决定用3个L*L的正方形塑料薄膜将小树遮起来
    我们不妨将山建立一个平面直角坐标系,设第 i 棵小树的坐标为(Xi,Yi)
    3个L*L的正方形的边要求平行于坐标轴,一个点如果在正方形的边界上,也算作被覆盖
    当然,我们希望塑料薄膜面积越小越好,即求L最小值
    

    看到这道题,很明显地可以看出来需要二分答案
    对于平面上的一些点,如果我们只使用一个尽量小的正方形覆盖它,那么这个正方形的大小和位置都是确定的
    现在的目标就是使用三个小一点的相同的正方形替换它,并保证所有点都被覆盖
    由于正方形的边必须与坐标轴平行,故小正方形至少有一条边所在的直线和大正方形的一条边所在的直线是重合的
    那么每个小正方形至少需要贡献一条边出来,因为只有3个小正方形,故一定至少有一个小正方形是贴着角的
    于是我们可以二分边长,check的时候暴力dfs判断小正方形分别在四个角时是否可以满足条件
    dfs的时候对点进行染色,方便回复到之前的状态

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define mid ((l+r)>>1)
    #define inf 1234567890
    using namespace std;
    
    int n;
    
    struct Object
    {
    	ll x,y;
    	int color;
    }a[20005];
    
    bool cmp(Object a,Object b)
    {
    	if(a.x==b.x) return a.y<b.y;
    	return a.x<b.x;
    }
    
    void update(ll minx,ll maxx,ll miny,ll maxy,int color)//更新这个正方形覆盖到的区域 
    {
    	for(register int i=1;i<=n;++i)
    	{
    		if(!a[i].color)
    		{
    			if((minx<=a[i].x&&a[i].x<=maxx)&&(miny<=a[i].y&&a[i].y<=maxy))
    				a[i].color=color;
    		}
    	}
    }
    
    void clear(int color)//用于撤销到dfs之前的状态 
    {
    	for(register int i=1;i<=n;++i)
    		if(a[i].color==color) a[i].color=0;
    }
    
    bool dfs(int cnt,int x)
    {
    	int minx=inf,miny=inf,maxx=-inf,maxy=-inf;
    	for(register int i=1;i<=n;++i)
    	{
    		if(!a[i].color)
    		{
    			if(a[i].x>maxx) maxx=a[i].x;
    			if(a[i].x<minx) minx=a[i].x;
    			if(a[i].y>maxy) maxy=a[i].y;
    			if(a[i].y<miny) miny=a[i].y;
    		}
    	}
    	ll lenx=maxx-minx;
    	ll leny=maxy-miny;
    	if(max(lenx,leny)<=x) return true;
    	if(cnt==3) return false;
    	
    	//枚举每一种方案是否可行 
    	
    	update(minx,minx+x,miny,miny+x,cnt);
    	if(dfs(cnt+1,x)) return true;
    	clear(cnt);
    	
    	update(minx,minx+x,maxy-x,maxy,cnt);
    	if(dfs(cnt+1,x)) return true;
    	clear(cnt);
    	
    	update(maxx-x,maxx,miny,miny+x,cnt);
    	if(dfs(cnt+1,x)) return true;
    	clear(cnt);
    	
    	update(maxx-x,maxx,maxy-x,maxy,cnt);
    	if(dfs(cnt+1,x)) return true;
    	clear(cnt);
    	
    	return false;
    }
    
    bool check(int x)//检验边长为 x 的薄膜是否符合要求 
    {
    	for(register int i=1;i<=n;++i) a[i].color=0;
    	return dfs(1,x);
    }
    
    template<class T>inline void read(T &res)
    {
    	char c;T flag=1;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
    	while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
    }
    
    int main()
    {
    	read(n);
    	for(register int i=1;i<=n;++i)
    	{
    		read(a[i].x);
    		read(a[i].y);
    	}
    	sort(a+1,a+n+1,cmp);
    	ll l=0,r=inf;
    	while(l<r)
    	{
    		if(check(mid)) r=mid;
    		else l=mid+1;
    	}
    	printf("%d
    ",mid);
    	return 0;
    }
    

    dfs里的变量一定要开局部!开全局的话死不瞑目啊!

  • 相关阅读:
    一键清理 Nexus 中无用的 Docker 镜像
    python 获取Linux和Windows硬件信息
    基于Docker安装破解版Jira(无坑)
    vim安装vundle时遇到的问题
    SpringBoot注解大全
    SpringBoot 应用JPA中的一些知识点
    记录初学SpringBoot使用Redis序列化的坑
    Spring Boot连接MySql报错
    钉钉扫码登录中的签名算法在python中的实现
    让Linux的history命令显示用户名和时间
  • 原文地址:https://www.cnblogs.com/tqr06/p/11593905.html
Copyright © 2020-2023  润新知