三角形面积并-扫描线,计算几何

本文详细解析了P4406三角形面积并问题的扫描线算法实现过程,通过求解图形交点并按横坐标排序,将问题转化为求梯形面积,有效解决了计算几何中的复杂面积计算问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

P4406 三角形面积并-扫描线,计算几何

题目描述

题目描述

题解

首先,我们将整个图形的各个交点求出来,然后按照横坐标升序排列,我们就可以发现两个点所在平行于y轴的直线之间的面积是梯形,然后扫描线扫一遍就好了。
注意
1,精度问题
2,对于特殊情况如下图,要特判
情况1
情况2

代码

#include<bits/stdc++.h>
#define M 109
using namespace std;
int n,cnt,tot;
double now,ans,last,p[M<<10];
const int inf=1e9;
const double eps=1e-12;
struct point{
	double x,y;
	point(double a=0,double b=0){x=a,y=b;}
	friend inline point operator+(const point &a,const point &b){return point(a.x+b.x,a.y+b.y);}
	friend inline point operator-(const point &a,const point &b){return point(a.x-b.x,a.y-b.y);}
	friend inline double operator*(const point &a,const point &b){return a.x*b.y-b.x*a.y;}
	friend inline double operator^(const point &a,const point &b){return a.x*b.x+a.y*b.y;}
	inline double dist(){return sqrt(x*x+y*y);}
}a[M],q[M];
struct line{
	point a,b;
}l[M][4];
bool check(double x,line a){
	if(x+eps>a.a.x&&x<eps+a.b.x) return true;
	else return false;
}
bool cmp(const point &a,const point &b){
	if(a.x!=b.x) return a.x<b.x;
	return a.y<b.y;
}
point inter(line a,line b){
	double k1,k2,t;
	k1=(b.b-a.a)*(a.b-a.a);
	k2=(a.b-a.a)*(b.a-a.a);
	t=k1/(k1+k2);
	return point(b.b.x+(b.a.x-b.b.x)*t,b.b.y+(b.a.y-b.b.y)*t);
}
double getans(double x,int type){
	tot=0;line w;
	w.a=point(x,-inf),w.b=point(x,inf);
    for(int i=1;i<=n;i++){
        if(l[i][type].b.x-l[i][type].a.x<eps&&x-l[i][type].a.x<eps) continue;
        double minx=inf,maxn=-inf;
        for(int j=1;j<=3;j++){
            if (x<l[i][j].a.x||x>l[i][j].b.x) continue;
            if (l[i][j].b.x-l[i][j].a.x<eps) continue;
            point t=inter(l[i][j],w);
            minx=min(minx,t.y),maxn=max(maxn,t.y);
        }if(maxn-minx>eps) q[++tot]=point(minx,maxn);
    }sort(q+1,q+tot+1,cmp);
    if(!tot) return 0;
    double L=q[1].x,R=q[1].y,sum=0;
    for(int i=2;i<=tot;i++){
        if(q[i].x-R>eps) sum+=R-L,L=q[i].x,R=q[i].y;
        else R=max(R,q[i].y);
    }sum+=R-L;
    return sum;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=3;j++) scanf("%lf%lf",&a[j].x,&a[j].y);
		sort(a+1,a+4,cmp);a[4]=a[1];
		for(int j=1;j<=3;j++){
			p[++cnt]=a[j].x;
			if(a[j].x>a[j+1].x+eps) swap(a[j],a[j+1]);
			l[i][j].a=a[j],l[i][j].b=a[j+1];
		}
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=3;j++)
			for(int k=i+1;k<=n;k++)
				for(int e=1;e<=3;e++){
					point t=inter(l[i][j],l[k][e]);
					//printf("%.2lf\n",t.x);
					if(check(t.x,l[i][j])&&check(t.x,l[k][e])) p[++cnt]=t.x;
				}//for(int i=1;i<=cnt;i++) printf("%.2lf ",p[i]);
	sort(p+1,p+cnt+1);
	cnt=unique(p+1,p+cnt+1)-p-1;
	for(int i=1;i<=cnt;i++){
		now=getans(p[i],1);
		if(i>1) ans+=(now+last)*0.5*(p[i]-p[i-1]);
		last=getans(p[i],2);
		//printf("%.2lf %.2lf\n",last,now);
	}printf("%.2lf\n",ans-(1e-5));
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值