2801. 三角形面积并

题目链接

2801. 三角形面积并

给出 \(n\) 个三角形,求它们并的面积。

输入格式

第一行为 \(n\),即三角形的个数。

以下 \(n\) 行,每行 \(6\) 个实数 \(x_1, y_1, x_2, y_2, x_3, y_3\),代表三角形的顶点坐标。

坐标均为不超过 \(10 ^ 6\) 的实数,输入数据保留 \(1\) 位小数。

输出格式

输出并的面积 \(u\),保留两位小数。

数据范围

\(1 \le n \le 100\)

输入样例:

2
0.0 0.0 2.0 0.0 1.0 1.0
1.0 0.0 3.0 0.0 2.0 1.0

输出样例:

1.75

解题思路

扫描线

将所有三角形的端点和交点预处理出来,然后扫描线处理每一小段之间的面积,可以发现每一小段之间是若干个梯形,梯形的高已经确定,需要分别计算上底和下底的总长度,对于左扫描线的上底总长度,对于一个贯穿该扫描线的三角形,需要先特判当前三角形是否存在一条竖直的直线恰好经过该点,其要求该三角形的另外一个端点在右边,否则求出两个点,右扫描线同理,最后区间和并求出各自的贡献即可

\(n\) 个三角形最后一个三角形增加的交点个数为 \(6n-6\),总的交点个数为 \(3n(n-1)\),则总点数为 \(3n^2\),故:

  • 时间复杂度:\(O(n^3logn)\)

代码

// Problem: 三角形面积并
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/2803/
// Memory Limit: 64 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=105;
const double eps=1e-8,inf=1e6;
typedef pair<double,double> PDD;
int n;
PDD tr[N][3],q[N];
PDD operator+(PDD a,PDD b)
{
	return {a.fi+b.fi,a.se+b.se};
}
PDD operator-(PDD a,PDD b)
{
	return {a.fi-b.fi,a.se-b.se};
}
PDD operator*(PDD a,double t)
{
	return {a.fi*t,a.se*t};
}
double operator*(PDD a,PDD b)
{
	return a.fi*b.se-b.fi*a.se;
}
double operator&(PDD a,PDD b)
{
	return a.fi*b.fi+a.se*b.se;
}
int sign(double x)
{
	if(fabs(x)<eps)return 0;
	if(x<0)return -1;
	return 1;
}
int dcmp(double x,double y)
{
	if(fabs(x-y)<eps)return 0;
	if(x<y)return -1;
	return 1;
}
bool on_segment(PDD p,PDD a,PDD b)
{
	return sign((p-a)&(p-b))<=0;
}
PDD get_line_intersection(PDD p,PDD v,PDD q,PDD w)
{
	if(!sign(v*w))return {inf,inf};
	PDD u=p-q;
	double t=w*u/(v*w);
	PDD o=p+v*t;
	if(!on_segment(o,p,p+v)||!on_segment(o,q,q+w))return {inf,inf};
	return o;
}
double line_area(double a,int side)
{
	int cnt=0;
	for(int i=1;i<=n;i++)
	{
		if(dcmp(tr[i][2].fi,a)<0||dcmp(a,tr[i][0].fi)<0)continue;
		if(!dcmp(tr[i][0].fi,a)&&!dcmp(tr[i][1].fi,a))
		{
			if(side)q[++cnt]={tr[i][0].se,tr[i][1].se};
		}
		else if(!dcmp(tr[i][1].fi,a)&&!dcmp(tr[i][2].fi,a))
		{
			if(!side)q[++cnt]={tr[i][1].se,tr[i][2].se};
		}
		else
		{
			double d[3];
			int t=0;
			for(int j=0;j<3;j++)
			{
				PDD o=get_line_intersection(tr[i][j],tr[i][(j+1)%3]-tr[i][j],{a,-inf},{0,inf*2});
				if(dcmp(o.fi,inf))d[t++]=o.se;
			}
			if(t)
			{
				sort(d,d+t);
				q[++cnt]={d[0],d[t-1]};
			}
		}
	}
	if(!cnt)return 0;
	for(int i=1;i<=cnt;i++)
		if(q[i].fi>q[i].se)swap(q[i].fi,q[i].se);
	sort(q+1,q+1+cnt);
	double res=0,st=q[1].fi,ed=q[1].se;
	for(int i=2;i<=cnt;i++)
		if(q[i].fi<=ed)ed=max(ed,q[i].se);
		else
		{
			res+=ed-st;
			st=q[i].fi,ed=q[i].se;
		}
	res+=ed-st;
	return res;
}
double range_area(double l,double r)
{
	return (line_area(l,1)+line_area(r,0))*(r-l)/2;
}
int main()
{
    scanf("%d",&n);
    vector<double> xs;
    for(int i=1;i<=n;i++)
    {
    	for(int j=0;j<3;j++)
    	{
    		scanf("%lf%lf",&tr[i][j].fi,&tr[i][j].se);
    		xs.pb(tr[i][j].fi);
    	}
    	sort(tr[i],tr[i]+3);
    }
    for(int i=1;i<=n;i++)
    	for(int j=1;j<i;j++)
    		for(int p=0;p<3;p++)
    			for(int q=0;q<3;q++)
    			{
    				PDD o=get_line_intersection(tr[i][p],tr[i][(p+1)%3]-tr[i][p],tr[j][q],tr[j][(q+1)%3]-tr[j][q]);
    				if(dcmp(o.fi,inf))xs.pb(o.fi);
    			}
    sort(xs.begin(),xs.end());
    double res=0;
    for(int i=1;i<xs.size();i++)
    	if(dcmp(xs[i-1],xs[i]))res+=range_area(xs[i-1],xs[i]);
    printf("%.2lf",res);
    return 0;
}
posted @ 2022-11-23 19:11  zyy2001  阅读(28)  评论(0编辑  收藏  举报