BZOJ 1845 CQOI 2005 三角形面积并 扫描线

来源:互联网 发布:appstore代充淘宝 编辑:程序博客网 时间:2024/05/17 08:08

题目大意:给出一些三角形,求这些三角形面积的并。


思路:应该可以辛普森积分,但是应该会很麻烦。。

以前扫描线就写过矩形的用数据结构维护的那种,和计算几何不占边,这次才是好好写了一次正宗的扫描线。不得不说这个算法还是很靠谱的。

其实这个思路不仅限于三角形面积的并,所有凸多边形的面积并应该都可以解决。

对于任意由线段组成的图形,对这个图形进行多次的划分,总可以将这个图形划分成梯形,面积也很好计算。那么按照什么划分呢?将所有三角形的边都求交点,不难发现,以这些点为划分依据的话,相邻两点之间一定是一个或者多个梯形或三角形(可以看成是特殊的梯形)。因为相邻两点之间不存在其他拐点。这样就把整个图划分成了很多梯形的和。

由于每次区间中的不一定是一个梯形,这些梯形的中位线总长需要将x=x‘这条线与所有三角形相交的区域求交,然后再计算。这就可以随便乱搞了,反正扫描线的总体时间复杂度是O(n^3)的,别比这个大就行了。这就是扫描线的基本思路。

有一些细节,刚开始写处处碰壁。。。

比如按照横坐标划分,就会有数据中有的三角形的边垂直于x轴,不好计算上底和下底,就不好计算面积了。可以转化一下,我们只需要计算这个梯形的中位线长。一定不会有一条边在梯形的中位线上,所以就避免了这个问题。

剩下的就可以尽情的乱搞了。。。


CODE:

#include <cmath>#include <cstdio>#include <cstring>#include <iomanip>#include <iostream>#include <algorithm>#define MAX 110#define EPS 1e-7using namespace std;#define DCMP(a) (fabs(a) < EPS)#define INRANGE(l,r,c) ((c) <= (r) && (c) >= (l))struct Point{double x,y;void Read() {scanf("%lf%lf",&x,&y);}Point(double _,double __):x(_),y(__) {}Point() {}bool operator <(const Point &a)const {return x < a.x;}Point operator +(const Point &a)const {return Point(x + a.x,y + a.y);}Point operator -(const Point &a)const {return Point(x - a.x,y - a.y);}Point operator *(double a)const {return Point(x * a,y * a);}}a,b,c,point[MAX * MAX * 10];int points;struct Line{Point p,v;double alpha;Line(Point _,Point __):p(_),v(__) {alpha = atan2(v.y,v.x);}Line() {}}line[MAX << 2];int lines;struct Interval{double l,r;Interval(double _,double __):l(_),r(__) {if(l > r)swap(l,r);}Interval() {}bool operator <(const Interval &a)const {if(l == a.l)return r < a.r;return l < a.l;}}interval[MAX];int intervals;inline double Cross(const Point &p1,const Point &p2){return p1.x * p2.y - p2.x * p1.y;}inline Point GetIntersection(const Line &a,const Line &b){Point u = a.p - b.p;double temp = Cross(b.v,u) / Cross(a.v,b.v);return a.p + a.v * temp;}inline void Sort(double &y1,double &y2,double &y3){double arr[] = {y1,y2,y3};sort(arr,arr + 3);y1 = arr[0],y2 = arr[1],y3 = arr[2];}struct Triangle{Line _a,b,c;Point p1,p2,p3;double w,s,a,d;void MakeTriangle(const Point &p,const Point &_p,const Point &__p) {p1 = p,p2 = _p,p3 = __p;_a = line[++lines] = Line(p1,p2 - p1);b = line[++lines] = Line(p2,p3 - p2);c = line[++lines] = Line(p3,p1 - p3);w = max(p1.y,max(p2.y,p3.y));s = min(p1.y,min(p2.y,p3.y));a = min(p1.x,min(p2.x,p3.x));d = max(p1.x,max(p2.x,p3.x));}void GetInterval(double x) {if(!INRANGE(a,d,x))return ;Line l(Point(x,0),Point(0,1));Point pa = GetIntersection(l,_a),pb = GetIntersection(l,b),pc = GetIntersection(l,c);double x1 = p1.x,x2 = p2.x,x3 = p3.x;if((INRANGE(x1,x2,x) || INRANGE(x2,x1,x)) && (INRANGE(x1,x3,x) || INRANGE(x3,x1,x)))interval[++intervals] = Interval(pa.y,pc.y);else if((INRANGE(x1,x2,x) || INRANGE(x2,x1,x)) && (INRANGE(x2,x3,x) || INRANGE(x3,x2,x)))interval[++intervals] = Interval(pa.y,pb.y);elseinterval[++intervals] = Interval(pb.y,pc.y);}}triangle[MAX];int cnt;int main(){cin >> cnt;for(int i = 1; i <= cnt; ++i) {a.Read();b.Read();c.Read();triangle[i].MakeTriangle(a,b,c);}for(int i = 1; i <= lines; ++i)for(int j = 1; j <= lines; ++j)if(!DCMP(Cross(line[i].v,line[j].v)))point[++points] = GetIntersection(line[i],line[j]);sort(point + 1,point + points + 1);double area = .0;for(int i = 2; i <= points; ++i) {if(DCMP(point[i].x - point[i - 1].x))continue;static double last_x = point[1].x;double now = .0,x = (point[i].x + last_x) / 2;intervals = 0;for(int j = 1; j <= cnt; ++j)triangle[j].GetInterval(x);sort(interval + 1,interval + intervals + 1);for(int j = 1; j <= intervals; ++j) {double l = interval[j].l,r = interval[j].r;int k;for(k = j + 1; k <= intervals; ++k) {if(interval[k].l <= r)r = max(r,interval[k].r);elsebreak;}now += r - l;j = k - 1;}area += now * (point[i].x - last_x);last_x = point[i].x;}cout << fixed << setprecision(2) << area - EPS << endl;return 0;}


0 0