hihocoder#1652 : 三角形面积和2(离散化+扫描线)

来源:互联网 发布:知了为什么是这个知 编辑:程序博客网 时间:2024/06/16 21:26

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

如下图所示,在X轴上方一共有N个三角形。这些三角形的底边与X轴重合,底边上两个顶点的坐标分别是(Li, 0)和(Ri, 0),底边的对顶点坐标是(Xi, Yi)。其中Li ≤ Xi ≤ Ri 且 Li < Ri


你能求出这些三角形覆盖的面积之和吗? (重叠部分只算一次)

输入

第一行包含一个整数N。(1 ≤= N ≤ 100)    

以下N行每行包含4个整数Li, Ri, Xi, Yi。(1 ≤ Li < Ri ≤ 100000 且 Xi ∈ [Li, Ri], 1 <= Yi ≤ 100000)

输出

覆盖的面积,保留2位小数。

样例输入
2  1 4 3 3  3 6 4 3
样例输出
8.25
思路:将每个三角形顶点及所有相交线段交点的x轴坐标算出并存在ax[i]中,排序去重后,就可以得到若干个以x=ax[i]为分界线的区间,只要求出所有线段与直线x=a[i]和直线x=a[i-1]的相交线段,取最高的那条线段(因为这个区间内不会存在其它的交点),即可求出[ax[i-1],ax[i]]区间的面积,如此往后扫描一遍即可得到答案。

#include<bits/stdc++.h>using namespace std;const int MAX=1e3;const double eps=1e-7;struct Point{double x,y;};struct Line{    Point st,en;}Li[MAX];double ax[10*MAX];double cross(Point a,Point b){return (a.x*b.y-a.y*b.x);}        //叉积Point Vector(Point a,Point b){return (Point){a.x-b.x,a.y-b.y};} //向量a-bdouble dot(Point a,Point b){return a.x*b.x+a.y*b.y;}            //点积int segmentin(Point a1,Point a2,Point b1,Point b2)              //判断线段是否相交{double c1=cross(Vector(a2,a1),Vector(b1,a1)),c2=cross(Vector(a2,a1),Vector(b2,a1));double c3=cross(Vector(b2,b1),Vector(a1,b1)),c4=cross(Vector(b2,b1),Vector(a2,b1));return (c1*c2<0||abs(c1*c2)<=eps)&&(c3*c4<=0||abs(c3*c4)<=eps);//如果等于0可能端点处有相交或线段重合}Point getaxi(Point a,Point b,Point c,Point d)                   //求线段ab与cd交点{    Point u=Vector(a,c);    Point v=Vector(b,a);    Point w=Vector(d,c);    double t=cross(w,u)/cross(v,w);    return (Point){a.x+v.x*t,a.y+v.y*t};}int main(){    int n,m=0,siz=0;    cin>>n;    for(int i=1;i<=n;i++)    {        double L,R,x,y;        scanf("%lf%lf%lf%lf",&L,&R,&x,&y);        Li[m++]=(Line){(Point){L,0},(Point){x,y}};        Li[m++]=(Line){(Point){x,y},(Point){R,0}};        ax[siz++]=L;        ax[siz++]=R;        ax[siz++]=x;    }    for(int i=0;i<m;i++)            //求出所有线段的交点    {        for(int j=i+1;j<m;j++)        {            if(segmentin(Li[i].st,Li[i].en,Li[j].st,Li[j].en)==0)continue;            ax[siz++]=getaxi(Li[i].st,Li[i].en,Li[j].st,Li[j].en).x;        }    }    sort(ax,ax+siz);    siz=unique(ax,ax+siz)-ax;    //for(int i=0;i<siz;i++)printf("x=%.2lf\n",ax[i]);    double ans=0;    for(int i=1;i<siz;i++)    {        Point p2=(Point){0,0};        Point p1=(Point){0,0};        for(int j=0;j<m;j++)//找出所有线段中与x=ax[i]和x=ax[i-1]相交所得到的最高的一条线段        {            if((ax[i]-Li[j].st.x>eps||abs(ax[i]-Li[j].st.x)<=eps)&&(Li[j].en.x-ax[i]>eps||abs(Li[j].en.x-ax[i])<=eps)&&(ax[i-1]-Li[j].st.x>eps||abs(ax[i-1]-Li[j].st.x)<=eps)&&(Li[j].en.x-ax[i-1]>eps||abs(Li[j].en.x-ax[i-1])<=eps))            {                Point now=getaxi(Li[j].st,Li[j].en,(Point){ax[i],0},(Point){ax[i],1000000});                Point pre=getaxi(Li[j].st,Li[j].en,(Point){ax[i-1],0},(Point){ax[i-1],1000000});                if((now.y-p2.y>eps||abs(now.y-p2.y)<=eps)&&(pre.y-p1.y>eps||abs(pre.y-p1.y)<=eps)){p2=now;p1=pre;}            }        }        //printf("pre:x=%.2lf y=%.2lf now:x=%.2lf y=%.2lf\n",p1.x,p1.y,p2.x,p2.y);        ans+=(p1.y+p2.y)*fabs(p1.x-p2.x)/2;    }    printf("%.2lf\n",ans);    return 0;}




阅读全文
1 0
原创粉丝点击