矩形切割


矩形切割———计算多个矩形的总面积

首先,看看这个:

没错,这是个面积为 \(4\) 的矩形,那么两个这样的矩形面积就是 \(8\)
但是真的是这样吗?

那么这是一个面积为 \(9\) 的和一个面积为 \(1\) 的矩形,他的面积可不是 \(9+1=10\),他重叠了!!
对于不重叠的矩形,把面积一个个加起来很简单
那对于重叠的矩形呢?开二维数组打标记?
那你就天真了!!!
你看看这道题
大体就是说在一个平面坐标系里,我给你\(N(N≤1000)\)个矩形,我告诉你他们左上角和右下角的坐标,然后然你求矩形覆盖区域的面积。
注意:坐标的范围在\(-10^8\)~\(10^8\)之间,来你给我开二维数组打个标记来。
很显然不行,那我们就会想到离散化缩小常数。
但这道题别想,超时,最多90分。
那咋办?

让我们这么想,我们有两个矩形,先把一个矩形放到坐标系中,然后发现另一个矩形与其有重叠部分,然后我们用后一个矩形把前一个矩形没有被遮盖的部分切下来,单独分成多个小矩形,然后把后一个矩形直接放上去。
再来一个矩形,用他分别去切我前面的所有矩形,然后放到坐标系里,以此类推,最后暴力枚举所有小矩形,把面积加起来就 \(OK\) 了。
我知道不形象,上图:

这两个矩形重叠了对吧,蓝色部分是矩形,而绿色部分不规则了。
那我们就让他规则!

现在全是矩形了,没有不规则的了。这就是矩形切割,那么怎么实现呢?

#include<bits/stdc++.h>
#define ll long long
#define Konnyaku std
using namespace Konnyaku;
ll read()
{
	ll x=0;bool f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f?x:(~x)+1;
}
struct node{
	ll x1,x2,y1,y2;
}a[100005];//存矩形
int n,top;
ll X1,X2,Y1,Y2;
void ADD(ll x1,ll x2,ll y1,ll y2){a[++top]=(node){x1,x2,y1,y2};}
void cuts(int jx,ll x1,ll x2,ll y1,ll y2,bool pd)//这个pd是为了分别进行切割横坐标和纵坐标。
{
	if(pd){//切割横坐标
		ll k1=max(a[jx].x1,x1),k2=min(a[jx].x2,x2);//分别比较来的矩形和被切割矩形的左上角,右下角两个横坐标
		if(k1>a[jx].x1)ADD(a[jx].x1,k1,a[jx].y1,a[jx].y2);//切下左边部分;
		if(k2<a[jx].x2)ADD(k2,a[jx].x2,a[jx].y1,a[jx].y2);//切下右边部分;
		cuts(jx,k1,k2,y1,y2,0);//切纵坐标去,因为矩形已经被切了一部分了,不能重复切,所以处理一下切矩形的矩形,把冗余部分去掉。
	}
	else {//切割纵坐标
		ll k1=min(a[jx].y1,y1),k2=max(a[jx].y2,y2);//比较纵坐标
		if(k1<a[jx].y1)ADD(x1,x2,a[jx].y1,k1);//切下上半部分;
		if(k2>a[jx].y2)ADD(x1,x2,k2,a[jx].y2);//切下下半部分;
	}
}
int main()
{
	n=read();
	X1=read();Y1=read();X2=read();Y2=read();
	ADD(X1,X2,Y1,Y2);//先把第一个矩形加进去
	for(int js=1;js<n;++js)
	{
		X1=read();Y1=read();X2=read();Y2=read();
		for(int i=1;i<=top;++i)//和每一个矩形作比较
		{
			if(X1>=a[i].x2||X2<=a[i].x1||Y1<=a[i].y2||Y2>=a[i].y1)continue;//如果没有重叠就不管
			cuts(i,X1,X2,Y1,Y2,1);//重叠了就切他
			a[i]=a[top];//当前这个矩形已经被切了,没有了,把他踢出去(用最后一个小矩形代替他)
			--top;//最后一个来到a[i]了,把a[top]踢出去
                        --i;//确保扫描到每一个矩形
		}
		ADD(X1,X2,Y1,Y2);//把新来的这个矩形加上。
	}
	ll ans=0;
	for(int i=1;i<=top;i++)//枚举每一个小矩形,因为不重叠了,所以直接把面积加起来即可
	ans+=(a[i].x2-a[i].x1)*(a[i].y1-a[i].y2);
	printf("%lld",ans);
}

于是我们就在大约 \(N^2\)(好像比这要多,因为矩形越来越多)的复杂度完成了一个常数极大的矩形覆盖面积问题。
\(VERY GOOD\)


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM