矩形切割


矩形切割———計算多個矩形的總面積

首先,看看這個:

沒錯,這是個面積為 \(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