1. 程式人生 > >bzoj-1845 三角形面積並

bzoj-1845 三角形面積並

題意:

給出n個三角形,求這n個三角形的面積並;

n<=100,座標範圍在10^6之內;

題解:

裸的掃描線處理面積並問題;

計算幾何的資料範圍通常不會出的很大,這種題都只是考慮如何處理資料;

這道題我似乎是被卡了一點精度,double換成long double才過掉;

至於解法第一句不是說完了嗎23333

咳。。首先就是為了方便處理,我們求出所有線段的交點;

然後用這些交點的橫座標將座標系劃分成一個個豎條;

這些豎條間隔的塊內,一定不會出現頂點,一定都是由梯形(三角形)組成的圖形;

這個性質實際上保證了一些東西,我們才可以用一些比較優美的方法解出這道題;

考慮列舉每一個塊,如何計算這個塊內的面積呢?

用中位線去截這個塊,得到的區間並長度就是中位線總長度,而總長度*塊的寬度就是面積了;

具體的細節理解還是寫程式碼比較好,程式碼實現也主要是細節;

時間複雜度O(n^3logn),但是寫這種題別太糾結複雜度,100範圍而已= =;

實現上還是要隨心所欲吧,計算幾何中寫對比寫的快重要得多咯;

程式碼:

#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 333
#define pr pair<ld,ld>
using namespace std;
typedef long double ld;
const ld EPS=1e-8;
const ld INF=1e100;
struct Point
{
	ld x,y;
	Point(){}
	Point(ld _,ld __):x(_),y(__){}
	void read()
	{
		double _,__;
		scanf("%lf%lf",&_,&__);
		x=_,y=__;
	}
	friend bool operator <(Point a,Point b)
	{
		if(fabs(a.x-b.x)<EPS)
		return a.y<b.y;
		return a.x<b.x;
	}
	friend Point operator +(Point a,Point b)
	{
		return Point(a.x+b.x,a.y+b.y);
	}
	friend Point operator -(Point a,Point b)
	{
		return Point(a.x-b.x,a.y-b.y);
	}
	friend Point operator *(ld a,Point b)
	{
		return Point(a*b.x,a*b.y);
	}
	friend ld operator *(Point a,Point b)
	{
		return a.x*b.x+a.y*b.y;
	}
	friend ld operator ^(Point a,Point b)
	{
		return a.x*b.y-a.y*b.x;
	}
}a[N][3],Poi[N*N];
struct Line
{
	Point p,v;
	Line(){}
	Line(Point _,Point __){p=_,v=__-_;}
	Point operator [](int k)
	{
		if(k)	return p+v;
		else	return p;
	}
	friend bool Cross(Line a,Line b)
	{
		return (a.v^b[0]-a.p)*(a.v^b[1]-a.p)<-EPS&&(b.v^a[0]-b.p)*(b.v^a[1]-b.p)<-EPS;
	}
	friend Point getP(Line a,Line b)
	{
		Point u=a.p-b.p;
		ld temp=(b.v^u)/(a.v^b.v);
		return a.p+temp*a.v;
	}
}l[N][3],T;
pr p[N];
int main()
{
	int n,m,i,j,k,x,y,cnt,tot;
	ld ans,last,A,B,sum;
	scanf("%d",&n);
	for(i=1,tot=0;i<=n;i++)
	{
		a[i][0].read(),a[i][1].read(),a[i][2].read();
		Poi[++tot]=a[i][0],Poi[++tot]=a[i][1],Poi[++tot]=a[i][2];
		sort(a[i],a[i]+3);
		if((a[i][2]-a[i][0]^a[i][1]-a[i][0])>EPS)
			l[i][0]=Line(a[i][0],a[i][2]),l[i][1]=Line(a[i][2],a[i][1]),l[i][2]=Line(a[i][1],a[i][0]);
		else
			l[i][0]=Line(a[i][2],a[i][0]),l[i][1]=Line(a[i][1],a[i][2]),l[i][2]=Line(a[i][0],a[i][1]);
	}
	for(i=1;i<=n;i++)
	{
		for(j=1;j<i;j++)
		{
			for(x=0;x<3;x++)
				for(y=0;y<3;y++)
				{
					if(Cross(l[i][x],l[j][y]))
						Poi[++tot]=getP(l[i][x],l[j][y]);
				}
		}
	}
	sort(Poi+1,Poi+tot+1);
	ans=0,last=Poi[1].x;
	T=Line(Point(0,-INF),Point(0,INF));
	for(i=2;i<=tot;i++)
	{
		T.p.x=(last+Poi[i].x)/2;
		for(j=1,cnt=0;j<=n;j++)
		{
			if(Cross(l[j][0],T))
			{
				A=getP(l[j][0],T).y;
				if(Cross(l[j][1],T))
					B=getP(l[j][1],T).y;
				else
					B=getP(l[j][2],T).y;
				if(A>B)	swap(A,B);
				p[++cnt]=pr(A,B);
			}
		}
		sort(p+1,p+cnt+1);
		for(j=1,sum=0,A=-INF;j<=cnt;j++)
		{
			if(p[j].first>A)
			{
				sum+=p[j].second-p[j].first;
				A=p[j].second;
			}
			else
			{
				if(p[j].second>A)
					sum+=p[j].second-A,A=p[j].second;
			}
		}
		ans+=(Poi[i].x-last)*sum;
		last=Poi[i].x;
	}
	printf("%.2lf\n",(double)ans);
	return 0;
}