多个限制的二分题 poj 矩形分割

Posted deadwooder

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多个限制的二分题 poj 矩形分割相关的知识,希望对你有一定的参考价值。

openoj 矩形分割

总时间限制:  1000ms  内存限制: 65536kB
描述

平面上有一个大矩形,其左下角坐标(0,0),右上角坐标(R,R)。大矩形内部包含一些小矩形,小矩形都平行于坐标轴且互不重叠。所有矩形的顶点都是整点。要求画一根平行于y轴的直线x=k(k是整数) ,使得这些小矩形落在直线左边的面积必须大于等于落在右边的面积,且两边面积之差最小。并且,要使得大矩形在直线左边的的面积尽可能大。注意:若直线穿过一个小矩形,将会把它切成两个部分,分属左右两侧。

输入
第一行是整数R,表示大矩形的右上角坐标是(R,R) (1 <= R <= 1,000,000)。
接下来的一行是整数N,表示一共有N个小矩形(0 < N <= 10000)。
再接下来有N 行。每行有4个整数,L,T, W 和 H, 表示有一个小矩形的左上角坐标是(L,T),宽度是W,高度是H (0<=L,T <= R, 0 < W,H <= R). 小矩形不会有位于大矩形之外的部分。
输出
输出整数n,表示答案应该是直线 x=n。 如果必要的话,x=R也可以是答案。
样例输入
1000
2
1 1 2 1
5 1 2 1
样例输出
5
大致题意:有一个大矩形中有多个不相交的小矩形,要找一个 x 值使得在 x 左边的小矩形面积  >= 右面积(如果于 x 相切分为两半),并且保证大矩形左面积经可能的大。
思路:很明显这是根据小矩形左面积递增关系进行二分的题,不过这个边界条件比较特殊。分两种情况:
1.存在 == 这时只需要找到 == 的最右值;(二分 <= 最右端值)
2不存在 == 这时二分取到了 < 的最右值 但答案是刚好  > 的最右值;
技术分享图片
1 while(l<=r){
2             mid = md;
3             ll ant = fid(mid);//左边小矩形的面积
4             if(ant<vsum-ant) l = mid+1;
5             else r = mid-1;
6         }
7         ll cnt = fid(l);
8         while(cnt==fid(l)&&l<=n) l++;
View Code

 

再聊聊这个二分:这种二分写法参见 博客园 https://www.cnblogs.com/luoxn28/p/5767571.html
他的这种思路就是只考虑二分的最终结果,进而判断二分方向与结束时的取值。
  大致讲一下
  
while(l<=r){
            mid = md;
            ll ant = fid(mid);//左边小矩形的面积
            if(ant<vsum-ant) l = mid+1;//在while中 l 是一直满足这个的 fid(l)<= key
            else r = mid-1;
}//二分结束 l,r 的位置关系变成  r,l 这时 l 刚好不再满足while内的关系
//所以此时 l 刚好 > key 所以 r 为 <= 最右端的值

最后再讲一下这题的坑  long long

和一个偷懒的地方   求小矩形面积的时候提前把总面积求了,二分时只求一半。
下面是我的完整代码
技术分享图片
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <queue>
 5 #include <cmath>
 6 #include <map>
 7 #include <set>
 8 #include <algorithm>
 9 #define ll long long
10 #define md l+(r-l>>1)
11 #define max(a,b) (a<b?b:a)
12 #define min(a,b) (a<b?a:b)
13 using namespace std;
14 const int maxn = 1e5+500;
15 struct node{
16     ll L,H,x;
17 }mp[maxn];
18 int n,m;
19 ll vsum;
20 bool cmp(node a,node b){
21     return a.x<b.x;
22 }
23 ll fid(ll t){
24     ll sum = 0;
25     for(int i=0;i<m;++i){
26         if(mp[i].x<t){//左边在
27             if(mp[i].x+mp[i].L<=t) sum+=mp[i].H*mp[i].L;//右边
28             else sum+=mp[i].H*(t-mp[i].x);
29         }
30         else break;
31     }
32     return sum;
33 }
34 int main(){
35     while(~scanf("%d%d",&n,&m)){
36         vsum = 0;int t;
37         for(int i=0;i<m;++i){
38             scanf("%lld%d%lld%lld",&mp[i].x,&t,&mp[i].L,&mp[i].H);
39             vsum += mp[i].L*mp[i].H;
40         }
41         sort(mp,mp+m,cmp);//以小矩形的左纵边x
42         ll l=0,r=n,mid;
43         while(l<=r){
44             mid = md;
45             ll ant = fid(mid);//左边小矩形的面积
46             if(ant<vsum-ant) l = mid+1;
47             else r = mid-1;
48         }
49         ll cnt = fid(l);
50         while(cnt==fid(l)&&l<=n) l++;
51         printf("%d
",l-1);
52     }
53     return 0;
54 }
View Code

 




以上是关于多个限制的二分题 poj 矩形分割的主要内容,如果未能解决你的问题,请参考以下文章

POJ百炼——1191棋盘分割

POJ2318判断点在直线哪一侧+二分查找区间

2017.4.23 1.矩形分割

POJ-2318 TOYS 计算几何 判断点在线段的位置

POJ 3122 (集训比赛2B_B题)解题报告

POJ 1191 棋盘分割(DP)