Rectangular split (two point answer)

Posted by eyalrosen on Thu, 03 Mar 2022 20:42:42 +0100

subject

There is a large rectangle on the plane, with the coordinates of the lower left corner (0,0) and the upper right corner (R,R). The large rectangle contains some small rectangles, which are parallel to the coordinate axis and do not overlap each other. The vertices of all rectangles are integral points. It is required to draw a straight line parallel to the y axis x=k (k is an integer), so that the area of these small rectangles on the left of the straight line must be greater than or equal to the area on the right, and the difference between the areas on both sides must be the smallest. Also, make the area of the large rectangle on the left of the straight line as large as possible. Note: if a straight line passes through a small rectangle, it will be cut into two parts, which belong to the left and right sides.

Input
The first line is the integer R, which indicates that the coordinates of the upper right corner of the large rectangle are (R,R).
The next line is the integer N, indicating a total of N small rectangles.
Then there are N lines. Each line has 4 integers L T W H
Indicates that there is a small rectangle whose upper left corner coordinates are (L,T), width is W and height is H
The small rectangle will not have a part outside the large rectangle.

Output
Output integer n, indicating that the answer should be straight line x=n. If necessary, x=R can also be the answer.

Sample Input 1
1000
2
1 1 2 1
5 1 2 1

Sample Output 1
5
Hint

1≤ R≤ 10^6
0<N≤ 10000
0≤L,T≤ R,0≤W,H≤ R
Time Limit
1000MS
Memory Limit
256MB

Topic meaning analysis

This problem first gives a large rectangle. There are many small rectangles in the large rectangle. The width of the large rectangle is R. find a dividing line in (0,R) to ensure that the sum of the areas of all small rectangles on the left of the dividing line is greater than or equal to the sum of the areas of all small rectangles on the right. The rectangle between the dividing lines is also calculated, and ensure that the sum of the areas of all small rectangles on the left and the sum of the areas of all small rectangles on the right is the smallest, That is (S left-S right) minimum! Finally, under the condition of ensuring the minimum (S left-S right), obtain the abscissa x of the division line as large as possible!

Problem solving ideas

First, enumerate x from 0, record all x that meet the meaning of the question, and finally find the maximum X!
Violent thought can satisfy small data, but R is 10 ^ 6. It is obviously impossible to pass through violence!

What shall I do?

Since linear search is not satisfied, take it for granted that binary search!

Let's look for the monotony of this problem first

First of all, as x increases, the area of all small rectangles on the left will increase, and the area of all small rectangles on the right will decrease, so S left-S right will increase as x increases!

With monotone relation, we can insert the template of binary answer. How to write the check function in if()?

We need to find the sum of the areas of all small rectangles on the left, and then compare it with the sum of the areas of all small rectangles,
If S left * 2 > = S total, it proves that x is larger, right=mid. if it is smaller than x, it needs left=mid!

How to minimize S left-S right and make x as large as possible?

Let's look at a picture first

From the picture, we can see that the first split line is obviously not optimal, and the second split line is optimal!
We just need to make x + + and keep the difference between S left and S right unchanged. See how much x can be added, which is the required maximum value of X!

Complete code

#include<cstdio>//uncle-lu
#include<algorithm>
#include<iostream>
using namespace std;
struct node{
	/*
	 *  x : x coordinate
	 *  y : y coordinate
	 *  h : height
	 *  w : width
	 */
	long long int x,y,h,w;
}a[10010];
long long int tot;
long long int r,n;

/* sum function
 * effect:
 *		Count the area and on the left of the split line
 * Variable:
 *		x : Split line
 *		sum_all : Sum of all matrices to the left of the split line
 */
long long int sum(long long int x)
{
	long long int sum_all=0;
	for(int i=1;i<=n;++i)
	{
		if(a[i].x+a[i].w<=x)
		{
			sum_all+=a[i].h*a[i].w;
		}
		else if(a[i].x<x&&a[i].x+a[i].w>x)
		{
			sum_all+=a[i].h*(x-a[i].x);
		}
		else break;
	}
	return sum_all;
}


int main()
{
	scanf("%lld",&r);
	scanf("%lld",&n);
	for(int i=1;i<=n;++i)
	{
		scanf("%lld%lld%lld%lld",&a[i].x,&a[i].y,&a[i].w,&a[i].h);
		tot+=(a[i].h*a[i].w);
	}
	/*
	 * ans_mean : Record the size of the left section split by the answer split line
	 * ans : Record answer split line
	 */
	long long int left=0,right=r+1,mid;
	long long int ans_mean;
	long long int ans=0;
	while(left+1<right)
	{
		mid=(left+right)/2;
		long long int sum_left=sum(mid);
		if(sum_left*2>=tot)
		{
			ans_mean=sum_left;
			ans=mid;
			right=mid;
		}
		else left=mid;
	}
	/*
	 * while Move the split line to the right as far as possible (deal with the part with blank space)
	 */
	while(ans<r&&sum(ans+1)==ans_mean)ans++;
	printf("%lld\n",ans);
	return 0;
}

If it's helpful to you, please give more praise and support. Thank you for watching!

Topics: Algorithm Interview