二分 - bailian 4136:矩形分割
题目链接
http://bailian.openjudge.cn/practice/4136/
分析
题目要一条竖线把这些矩形分割,要左边面积大于等于右边面积,两边面积还要尽量接近。这个问法和前面有道题问法很像,前几条博客里有道题说:给一个有序序列,再给一个数,要求输出序列中离这个数最近的数。左边面积等于右边面积,不就是给的这个数在序列中出现了;两边面积尽量接近,就好比在后者问题中给的数在序列没有出现,找出离给的数最近的序列元素。
回到这道题,这个题可以用二分法的原因在于:如果一条线x = k能将小矩形们分为左大右小,那在x = k右边的线一定可以将所有小矩形分为左大右小。分成左小右大的情况也是相似的。
这道题需要注意的一点是,求左右面积差的时候,一定要使用long long类型,int 类型不够保存。
解题代码
//
// main.cpp
// 4136:矩形分割 4136:矩形分割
//
// Created by apple on 2020/3/30.
// Copyright © 2020 apple. All rights reserved.
//
#include <cstring>
#include <cstdio>
long long area(int );
int r, n;
struct rectange{
int l, t, w, h;
}p[10010];
int main(){
scanf("%d%d", &r, &n);
for(int i = 0; i < n; i++){
scanf("%d %d %d %d", &p[i].l, &p[i].t, &p[i].w, &p[i].h);
}
int low = 0, high = r, mid;
while(low <= high){
mid = low + (high - low) / 2;
if(area(mid) < 0){
low = mid + 1;
}
else if(area(mid) > 0){
high = mid - 1;
}
else
break;
}
int x = 0;
if(low <= high)
x = mid;
else
x = low;
while(area(x) == area(x + 1) && x<r)
x++;
printf("%d\n", x);
return 0;
}
long long area(int mid){
long long lsum = 0, rsum = 0;
for(int i = 0; i < n; i++){
if(p[i].l + p[i].w <= mid){
lsum += p[i].w * p[i].h;
}
else if(p[i].l >= mid){
rsum += p[i].w * p[i].h;
}
else{
lsum += p[i].h * (mid - p[i].l);
rsum += p[i].h * (p[i].l + p[i].w - mid);
}
}
return lsum - rsum;
}
你若笃定,世界便不浮躁。