【bzoj1845】三角形面积并 计算几何

       这应该算是一道很经典的计算几何题吧。

       另外,类似的做法可以拓展到多边形面积并。

       首先求出所有的交点,然后用所有顶点的x坐标和交点的x坐标把原来的图形分割出来。显然,每一个分割块中,一定由若干个梯形组成(可能退化)。

       那么对于每一个分割块,把梯形简化为其中位线,求中位线的覆盖再呈上分割块的宽度,累加入答案即可。

       采用O(NlogN)的线段覆盖,加上分割线有O(N^2)条,总时间O(N^3logN)。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 1e100
#define ld long double
#define N 355
using namespace std;

int n,cnt,tot;
struct point{ ld x,y; }a[N][3],c[N],p[N*N];
struct line{ point p,v; }l[N][3];
point operator -(point u,point v){
	u.x-=v.x; u.y-=v.y; return u;
}
point operator +(point u,point v){
	u.x+=v.x; u.y+=v.y; return u;
}
ld crs(point u,point v){ return u.x*v.y-u.y*v.x; }
bool havitr(line x,line y){
	return crs(y.p-x.p,x.v)*crs(y.p+y.v-x.p,x.v)<0 && crs(x.p-y.p,y.v)*crs(x.p+x.v-y.p,y.v)<0;
}
point itr(line x,line y){
	ld t=crs(y.v,x.p-y.p)/crs(x.v,y.v);
	x.p.x+=t*x.v.x; x.p.y+=t*x.v.y; return x.p;
}
bool cmp(point u,point v){
	return u.x<v.x || u.x==v.x && u.y<v.y;
}
void add(int i,int k,int u,int v){ l[i][k].p=a[i][u]; l[i][k].v=a[i][v]-a[i][u]; }
int main(){
	scanf("%d",&n); int i,j,x,y;
	for (i=1; i<=n; i++){
		for (j=0; j<3; j++){
			double u,v; scanf("%lf%lf",&u,&v);
			a[i][j].x=u; a[i][j].y=v;
			p[++cnt]=a[i][j];
		}
		sort(a[i],a[i]+3,cmp);
		if (crs(a[i][2]-a[i][0],a[i][1]-a[i][0])>0){
			add(i,0,0,2); add(i,1,2,1); add(i,2,1,0);
		} else{ add(i,0,2,0); add(i,1,0,1); add(i,2,1,2); }
	}
	for (i=2; i<=n; i++)
		for (j=1; j<i; j++)
			for (x=0; x<3; x++) for (y=0; y<3; y++)
				if (havitr(l[i][x],l[j][y])) p[++cnt]=itr(l[i][x],l[j][y]);
	sort(p+1,p+cnt+1,cmp);
	ld ans=0; int tot;
	line t; t.v.x=0; t.v.y=2*inf; t.p.y=-inf;
	for (i=2; i<=cnt; i++) if (p[i].x!=p[i-1].x){
		t.p.x=(p[i-1].x+p[i].x)/2; tot=0;
		for (j=1; j<=n; j++) if (havitr(l[j][0],t)){
			ld u=itr(l[j][0],t).y,v=(havitr(l[j][1],t))?itr(l[j][1],t).y:itr(l[j][2],t).y;
			if (u>v) swap(u,v);
			c[++tot].x=u; c[tot].y=v;
		}
		sort(c+1,c+tot+1,cmp);
		ld u=-inf,v=-inf,tmp=0;
		for (j=1; j<=tot; j++)
			if (c[j].x>v){
				tmp+=v-u; u=c[j].x; v=c[j].y;
			} else if (c[j].y>v) v=c[j].y;
		tmp+=v-u; ans+=tmp*(p[i].x-p[i-1].x);
	}
	printf("%.2f\n",(double)ans);
	return 0;
}


by lych

2016.3.5

你可能感兴趣的:(计算几何,线段覆盖)