bzoj1052 覆盖问题 二分答案 dfs

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1052

题意:找到一个最小边长,使得以此为边长$3$个正方形可以覆盖平面上给定的一些点。

华丽爆零……

首先看到最小果断想二分答案……

然后我们证明一个东西……

首先,根据鸽巢原理,$3$个正方形覆盖由所有点构成的最小矩形一定有一个正方形是压着至少两条边的……

然后不外乎两种情况……

1、压的是对边,那么每个都在压对边,有一个正方形会压到三条边,就会压到一个角……

2、压的是邻边,一定会压到一个角……

那么方案就出来了……对于每个正方形,枚举压到了哪个角然后暴力排除每一个被覆盖的点……之后递归搜索新的矩形并继续……

问题得解……

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn=(int)1e6+5;
 7 int x[maxn],y[maxn],n,ax[4],ay[4],ajia[4],ajian[4];bool vis[maxn],now[4][maxn];int titai[3]={0,1,-1};
 8 bool dfs(int num,int val)
 9 {
10     if(num>3)
11     {
12         for(int i=1;i<=n;i++)
13             if(!vis[i])return 0;
14         return 1;
15     }
16     int maxx=-2147483647,minx=2147483647,maxy=-2147483647,miny=2147483647;
17     for(int i=1;i<=n;i++)
18         if(!vis[i])maxx=max(maxx,x[i]),minx=min(minx,x[i]),maxy=max(maxy,y[i]),miny=min(miny,y[i]);
19     if(max(maxx-minx,maxy-miny)<=val)return 1;
20     else if(num==3)return 0;
21     for(int i=1;i<=2;i++)
22         for(int j=1;j<=2;j++)
23         {
24             ajia[num]=titai[i],ajian[num]=titai[j];
25             if(ajia[num]==1&&ajian[num]==1)ax[num]=minx,ay[num]=miny;
26             else if(ajia[num]==1&&ajian[num]==-1)ax[num]=minx,ay[num]=maxy;
27             else if(ajia[num]==-1&&ajian[num]==1)ax[num]=maxx,ay[num]=miny;
28             else if(ajia[num]==-1&&ajian[num]==-1)ax[num]=maxx,ay[num]=maxy;
29             for(int i=1;i<=n;i++)
30                 if(!vis[i]&&((ajia[num]==1&&ajian[num]==1&&ax[num]<=x[i]&&ay[num]<=y[i]&&ax[num]+val>=x[i]&&ay[num]+val>=y[i])||(ajia[num]==1&&ajian[num]==-1&&ax[num]<=x[i]&&ay[num]>=y[i]&&ax[num]+val>=x[i]&&ay[num]-val<=y[i])||(ajian[num]==1&&ajia[num]==-1&&ay[num]<=y[i]&&ax[num]>=x[i]&&ay[num]+val>=y[i]&&ax[num]-val<=x[i])||(ajian[num]==-1&&ajia[num]==-1&&ay[num]>=y[i]&&ax[num]>=x[i]&&ay[num]-val<=y[i]&&ax[num]-val<=x[i])))vis[i]=now[num][i]=1;
31             int t=dfs(num+1,val);
32             for(int i=1;i<=n;i++)if(now[num][i])vis[i]=now[num][i]=0;
33             if(t)return 1;
34         }
35     return 0;
36 }
37 bool check(int val)
38 {
39     return dfs(1,val);
40 }
41 int haha()
42 {
43     scanf("%d",&n);int maxx=-2147483647,minx=2147483647,maxy=-2147483647,miny=2147483647;
44     for(int i=1;i<=n;i++)scanf("%d%d",&x[i],&y[i]),maxx=max(maxx,x[i]),minx=min(minx,x[i]),maxy=max(maxy,y[i]),miny=min(miny,y[i]);
45     int l=1,r=max(maxx-minx,maxy-miny),mid;
46     while(l<=r)
47     {
48         mid=(l+r)>>1;
49         if(check(mid))r=mid-1;
50         else l=mid+1;
51     }
52     printf("%d\n",l);
53 }
54 int sb=haha();
55 int main(){;}

bzoj1052

时间: 2024-10-09 18:50:28

bzoj1052 覆盖问题 二分答案 dfs的相关文章

BZOJ 1052 HAOI2007 覆盖问题 二分答案+DFS

题目大意:给定n个点,用三个边长相同的正方形覆盖所有点,要求正方形边界与坐标轴垂直,求正方形边长的最小值 最大值最小,很明显二分答案 但是验证是个问题 考虑只有三个正方形,故用一个最小矩形覆盖这三个正方形时至少有一个在角上 若有四个正方形该结论不成立 于是我们采用DFS的方式 每次用一个最小的矩形覆盖所有的点,枚举矩形的四个角 将正方形填进去 由于最大深度是3,所以时间上完全可以承受 #include<cstdio> #include<cstring> #include<io

BZOJ 1486: [HNOI2009]最小圈( 二分答案 + dfs判负圈 )

二分答案m, 然后全部边权减掉m, 假如存在负圈, 那么说明有平均值更小的圈存在. 负圈用dfs判断. --------------------------------------------------------------------------- #include<bits/stdc++.h> #define rep(i, n) for(int i = 0; i < n; ++i) #define clr(x, c) memset(x, c, sizeof(x)) #define

BZOJ 1486 HNOI2009 最小圈 二分答案+DFS

题目大意:裸的最优比例环 直接二分答案+SPFA 这样会T 因为数据卡SPFA SPFA在负环非常小的时候会退化成Bellman-Ford 时间复杂度是O(nm) (好像是O(n*m^2)?我忘了)的 换一种方法 枚举每个点 从每个点开始DFS 只沿着能将指向的点dis减小的边搜索 搜到栈中的点就返回true 期望复杂度O(n^2) 最坏复杂度O(2^n) 这种东西能过我也是醉了- - #include <cstdio> #include <cstring> #include &l

BZOJ 1052 HAOI2007 覆盖问题 二分法答案+DFS

标题效果:特定n点.涵盖所有的点与同方三面.斧头要求方垂直边界,最小平方的需求方长值 最大值至少.答案是很明显的二分法 但验证是一个问题 考虑仅仅有三个正方形,故用一个最小矩形覆盖这三个正方形时至少有一个在角上 若有四个正方形该结论不成立 于是我们採用DFS的方式 每次用一个最小的矩形覆盖全部的点,枚举矩形的四个角 将正方形填进去 因为最大深度是3,所以时间上全然能够承受 #include<cstdio> #include<cstring> #include<iostream

[BZOJ 1486][HNOI2009]最小圈(二分答案+dfs写的spfa判负环)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1486 分析:容易想到先二分答案x,然后把所有边的权值-x,那么如果图中存在权值和为0的环那就最好不过了,说明我们找到了这个环,但如果存在负环,则说明我们的x还可以更小,如果不存在负环,则说明我们的x大了.所以接下来的问题是如何判断负环了.可以用spfa,但bfs做的会TLE,因为每个点的松弛不具有连续性,如果用dfs写的话则效率会大大提高.2009集训队论文中有涉及.

hdu 2295 dlx重复覆盖+二分答案

题目大意: 有一堆雷达工作站,安放至多k个人在这些工作站中,找到一个最小的雷达监控半径可以使k个工作人所在的雷达工作站覆盖所有城市 二分半径的答案,每次利用dlx的重复覆盖来判断这个答案是否正确 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #include <queue> 6 #include <climits

BZOJ 2525 Poi2011 Dynamite 二分答案+树形贪心

题目大意:给定一棵树,有一些点是关键点,要求选择不超过m个点,使得所有关键点到最近的选择的点距离最大值最小 二分答案,问题转化为: 给定一棵树,有一些点是关键点,要求选择最少的点使得每个关键点到选择的点的距离不超过limit 然后我们贪心DFS一遍 对于以一个节点为根的子树,有三种状态: 0.这棵子树中存在一个选择的点,这个选择的点的贡献还能继续向上传递 1.这棵子树中存在一个未被覆盖的关键点,需要一些选择的点去覆盖他 2.这棵子树中既没有能继续向上传递的选择的点也不存在未覆盖的关键点 是不是少

NOIp2015 运输计划 [LCA] [树上差分] [二分答案]

我太懒了 吃掉了题面 题解 & 吐槽 一道很好的树上差分练习题. 不加fread勉强a过bzoj和luogu的数据,加了fread才能在uoj里卡过去. 可以发现,答案则是运输计划里花费的最大值,最大值最小,便是二分答案的标志. 那么该怎么check呢... 我们得找出所有超过限制的计划,这个过程可以在LCA倍增的过程中预处理出来. 然后再找出一些被这些计划都覆盖的边,找到最大的那条边,如果最大的计划花费减去最大的那条边小于x,那么x就是可行的. 但是该怎么找到那些被计划都覆盖的边呢... 我们

POJ 3080 Blue Jeans(后缀数组+二分答案)

[题目链接] http://poj.org/problem?id=3080 [题目大意] 求k个串的最长公共子串,如果存在多个则输出字典序最小,如果长度小于3则判断查找失败. [题解] 将所有字符串通过拼接符拼成一个串,做一遍后缀数组,二分答案,对于二分所得值,将h数组大于这个值的相邻元素分为一组,判断组内元素是否覆盖全字典,是则答案成立,对于答案扫描sa,输出第一个扫描到的子串即可. [代码] #include <cstdio> #include <cstring> #inclu