#扫描线,计算几何#洛谷 4406 [CQOI2005] 三角形面积并

题目传送门


分析

将三角形沿 \(x=k\) 利用扫描线分成若干个线段,那么面积并就是各个梯形的合并,求出上底与下底之和乘高除以二。

而这些线只可能是三角形的顶点或是交点,一共 \(O(n^2)\) 个,直接对这么多条关键直线求出底的长度,利用交点个数判断,

按照线段左端点从小到大排序求出当前最大右端点即可计算,时间复杂度 \(O(n^3\log n)\),也许里面难度最大的是两线段求交点吧。


代码

#include <iostream>
#include <iomanip>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=111;
typedef long double ld;
const ld COS=cos(0.626),SIN=sin(0.626);
struct Point{
	ld x,y;
	Point operator -(const Point &t)const{
		return (Point){x-t.x,y-t.y};
	}
}a[N][3];
int n,m; ld b[N*N*9],ans; pair<ld,ld>B[N];
ld cj(Point x,Point y){return x.x*y.y-x.y*y.x;}
Point intersect(int &inner,Point A,Point B,Point C,Point D){
	ld S1=cj(C-A,D-A),S2=cj(D-B,C-B);
	if (fabs(S1+S2)<1e-6) {inner=0; return A;}
	ld ratio=S1/(S1+S2);
	Point P=(Point){A.x+(B.x-A.x)*ratio,A.y+(B.y-A.y)*ratio};
	if (ratio<0||ratio>1||(P.x<C.x&&P.x<D.x)||(P.x>C.x&&P.x>D.x)) inner=0;
	    else inner=1;
	return P;
}
ld calc(ld now){
	int tot=0;
	for (int i=1,inner;i<=n;++i){
		ld Y[3]; int TOT=0;
		for (int j1=0;j1<3;++j1)
		for (int j2=j1+1;j2<3;++j2){
			Point P=intersect(inner,(Point){now,-1e9},(Point){now,1e9},a[i][j1],a[i][j2]);
			if (inner) Y[TOT++]=P.y;
		}
		sort(Y,Y+TOT);
		if (TOT==2&&Y[1]-Y[0]>1e-6) B[++tot]=make_pair(Y[0],Y[1]);
		else if (TOT==3){
			if (Y[1]-Y[0]>1e-6) B[++tot]=make_pair(Y[0],Y[1]);
			    else B[++tot]=make_pair(Y[1],Y[2]);
		}
	}
	sort(B+1,B+1+tot);
	ld lst=B[1].first,ans=0;	
	for (int i=1;i<=tot;++i){
		if (B[i].second<=lst) continue;
		ans+=B[i].second-max(B[i].first,lst);
		lst=B[i].second;
	}
	return ans;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for (int i=1;i<=n;++i)
	for (int j=0;j<3;++j){
		ld x,y; cin>>x>>y;
		a[i][j].x=x*COS+y*SIN;
		a[i][j].y=y*COS-x*SIN;
		b[++m]=a[i][j].x;
	}
	for (int i1=1;i1<=n;++i1)
	for (int j1=0;j1<3;++j1)
	for (int J1=j1+1;J1<3;++J1)
	for (int i2=i1+1;i2<=n;++i2)
	for (int j2=0;j2<3;++j2)
	for (int J2=j2+1,inner;J2<3;++J2){
		Point P=intersect(inner,a[i1][j1],a[i1][J1],a[i2][j2],a[i2][J2]);
		if (inner) b[++m]=P.x;
	}
	sort(b+1,b+1+m),m=unique(b+1,b+1+m)-b-1;
	ld lst=calc(b[1]);
	for (int i=2;i<=m;++i){
		ld now=calc(b[i]);
		ans+=(now+lst)*(b[i]-b[i-1])/2;
		lst=now;
	}
	cout<<fixed<<setprecision(2)<<ans;
	return 0;
} 
posted @ 2025-07-13 03:32  lemondinosaur  阅读(12)  评论(0)    收藏  举报