bzoj 1845: [Cqoi2005] 三角形面积并 扫描线

1845: [Cqoi2005] 三角形面积并

Time Limit: 3 Sec  Memory Limit: 64 MB
Submit: 848  Solved: 206
[Submit][Status][Discuss]

Description

给出n个三角形,求它们并的面积。

Input

第一行为n(N < = 100), 即三角形的个数 以下n行,每行6个整数x1, y1, x2, y2, x3, y3,代表三角形的顶点坐标。坐标均为不超过10 ^ 6的实数,输入数据保留1位小数

Output

输出并的面积u, 保留两位小数

Sample Input

2
0.0 0.0 2.0 0.0 1.0 1.0
1.0 0.0 3.0 0.0 2.0 1.0

Sample Output

1.75

  以前一直听说有一个除辛普森积分外的求面积的方法,现在才终于编了一次,大概思路就是通过扫描线,将答案转换成一个一个梯形相加。

  另:unique的函数参数应该传进去等于符号的比较函数,而不是大于符号,每次都会搞错。。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
#define MAXN 1000
#define sqr(x) ((x)*(x))
#define eps 1e-10
typedef double real;
inline int sgn(real x)
{
        if (abs(x)<eps)
                return 0;
        return x<0?-1:1;
}
struct point
{
        real x,y;
        point(real x,real y):x(x),y(y){}
        point(){}
        void read()
        {
                scanf("%lf%lf",&x,&y);
        }
};
real dis(point p1,point p2)
{
        return sqrt(sqr(p1.x-p2.x)+sqr(p1.y-p2.y));
}
struct line
{
        point ps;
        real x,y;
        line(){}
        line(point p1,point p2)
        {
                ps=p1;
                x=p2.x-p1.x;
                y=p2.y-p1.y;
        }
        point spos()
        {
                return ps;
        }
        point tpos()
        {
                return point(ps.x+x,ps.y+y);
        }
        bool inside(point pt)
        {
                return sgn(sqrt(x*x+y*y)-dis(ps,pt)-dis(tpos(),pt))==0;
        }
        point get_point(real xx)
        {
                return point(xx,ps.y+y/x*(xx-ps.x));
        }
        void operator *=(real k)
        {
                x*=k;y*=k;
        }
        void print()
        {
                printf("Line:[%.2lf,%.2lf]->[%.2lf,%.2lf]\n",ps.x,ps.y,ps.x+x,ps.y+y);
        }
}lst[MAXN];
int topl=-1;
real xmul(line l1,line l2)
{
        return l1.x*l2.y-l1.y*l2.x;
}
line operator -(line l1)
{
        l1.ps=l1.tpos();
        l1.x=-l1.x;
        l1.y=-l1.y;
        return l1;
}
bool parallel(line l1,line l2)
{
        return !sgn(xmul(l1,l2));
}
point crossover(line l1,line l2)
{
        real s1=-xmul(line(l2.spos(),l1.spos()),l1);
        real s2=xmul(line(l2.tpos(),l1.spos()),l1);
        return point(l2.ps.x+l2.x*s1/(s1+s2), l2.ps.y+l2.y*s1/(s1+s2));
}
point pl[MAXN*MAXN];
int topp=-1;
bool cmp_x(point p1,point p2)
{
        return sgn(p1.x-p2.x)<0;
}
bool equal_x(point p1,point p2)
{
        return sgn(p1.x-p2.x)==0;
}
line seq[MAXN];
bool cmp_line(line l1,line l2)
{
        point p1,p2;
        if (l1.x>=0)
                p1=l1.spos();
        else
                p1=l1.tpos();
        if (l2.x>=0)
                p2=l2.spos();
        else
                p2=l2.tpos();
        if (sgn(p1.y-p2.y)==0)
        {
                if (l1.x>=0)
                        p1=l1.tpos();
                else
                        p1=l1.spos();
                if (l2.x>=0)
                        p2=l2.tpos();
                else
                        p2=l2.spos();
                return p1.y>p2.y;
        }else
        {
                return p1.y>p2.y;
        }
}

int main()
{
        freopen("input.txt","r",stdin);
        int n;
        point p1,p2,p3;
        scanf("%d",&n);
        for (int i=0;i<n;i++)
        {
                p1.read();
                p2.read();
                p3.read();
                lst[++topl]=line(p1,p2);
                lst[++topl]=line(p2,p3);
                lst[++topl]=line(p3,p1);
                if (xmul(-lst[topl-1],lst[topl])<0)
                {
                        lst[topl]=-lst[topl];
                        lst[topl-1]=-lst[topl-1];
                        lst[topl-2]=-lst[topl-2];
                }
        }
        point pt;
        for (int i=0;i<=topl;i++)
        {
                for (int j=i+1;j<=topl;j++)
                {
                        pt=crossover(lst[i],lst[j]);
                        if (lst[i].inside(pt) && lst[j].inside(pt))
                                pl[++topp]=pt;
                }
        }
        sort(pl,pl+topp+1,cmp_x);
        topp=unique(pl,pl+topp+1,equal_x)-pl-1;//***
        real a,b;
        line lt;
        real ans=0;
        for (int i=1;i<=topp;i++)
        {
                a=pl[i-1].x;
                b=pl[i].x;
                int tops=-1;
                for (int j=0;j<=topl;j++)
                {
                        lt=lst[j];
                        if ((lt.spos().x<lt.tpos().x && sgn(lt.spos().x-a)<=0 && sgn(b-lt.tpos().x)<=0)
                                        || (lt.spos().x>lt.tpos().x && sgn(lt.tpos().x-a)<=0 && sgn(b-lt.spos().x)<=0))
                        {
                                if (lt.spos().x<lt.tpos().x)
                                {
                                        lt.ps=lt.get_point(a);
                                        lt*=(b-a)/lt.x;
                                        seq[++tops]=lt;
                                }else
                                {
                                        lt.ps=lt.get_point(b);
                                        lt*=(a-b)/lt.x;
                                        seq[++tops]=lt;
                                }
                        }
                }
                sort(seq,seq+tops+1,cmp_line);
            /*    printf("Segment:%.2lf %.2lf\n",a,b);
                for (int j=0;j<=tops;j++)
                        seq[j].print();*/
                int cnt=0;
                for (int j=0;j<=tops;j++)
                {
                        if (seq[j].x>=0)
                        {
                                cnt++;
                                if (cnt==1)
                                        ans+=(seq[j].spos().y+seq[j].tpos().y)*seq[j].x/2;
                        }
                        else
                        {
                                cnt--;
                                if (cnt==0)
                                        ans+=(seq[j].spos().y+seq[j].tpos().y)*seq[j].x/2;
                        }
                }
        }
        printf("%.2lf\n",ans);
        return 0;
}
时间: 2024-10-12 03:00:44

bzoj 1845: [Cqoi2005] 三角形面积并 扫描线的相关文章

BZOJ 1845: [Cqoi2005] 三角形面积并 [计算几何 扫描线]

1845: [Cqoi2005] 三角形面积并 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 1151  Solved: 313[Submit][Status][Discuss] Description 给出n个三角形,求它们并的面积. Input 第一行为n(N < = 100), 即三角形的个数 以下n行,每行6个整数x1, y1, x2, y2, x3, y3,代表三角形的顶点坐标.坐标均为不超过10 ^ 6的实数,输入数据保留1位小数 Out

BZOJ 1845 [Cqoi2005] 三角形面积并 计算几何扫描线

题意:链接 方法:扫描线 解析: 扫描线裸题. 先搞出所有边. 之后求一下所有边的交点. 按照x坐标排序. 之后每两个不同的坐标间的面积其实就是中间截出来的所有梯形以及三角形的中位线的和乘以高度. 至于中位线,再用这个与y轴平行的线截一下所有的三角形即可. 统计长度.把所有的加起来即可. 卡精! 代码: #include <cmath> #include <cstdio> #include <iomanip> #include <cstring> #incl

bzoj 1845: [Cqoi2005] 三角形面积并

https://www.lydsy.com/JudgeOnline/problem.php?id=1845 将所有三角形的端点.交点按x坐标排序,从左往右扫描线 每相邻两根扫描线a和b之间的形状是若干个不相交的梯形或三角形 用公式:中位线长度*高 计算面积 高就是两条扫描线之间的距离 中位线,计算x=(xa+xb)/2 被覆盖了多长即可 因为已将三角形端点考虑在内,所以线段相交只需要考虑规范相交即可 直接套lrj的板子 #include<cmath> #include<cstdio>

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

题目大意:给出一些三角形,求这些三角形面积的并. 思路:应该可以辛普森积分,但是应该会很麻烦.. 以前扫描线就写过矩形的用数据结构维护的那种,和计算几何不占边,这次才是好好写了一次正宗的扫描线.不得不说这个算法还是很靠谱的. 其实这个思路不仅限于三角形面积的并,所有凸多边形的面积并应该都可以解决. 对于任意由线段组成的图形,对这个图形进行多次的划分,总可以将这个图形划分成梯形,面积也很好计算.那么按照什么划分呢?将所有三角形的边都求交点,不难发现,以这些点为划分依据的话,相邻两点之间一定是一个或

BZOJ1845CQOI2005三角形面积并

1845: [Cqoi2005] 三角形面积并 Description 给出n个三角形,求它们并的面积. Input 第一行为n(N < = 100), 即三角形的个数 以下n行,每行6个整数x1, y1, x2, y2, x3, y3,代表三角形的顶点坐标.坐标均为不超过10 ^ 6的实数,输入数据保留1位小数 Output 输出并的面积u, 保留两位小数 Sample Input 2 0.0 0.0 2.0 0.0 1.0 1.0 1.0 0.0 3.0 0.0 2.0 1.0 Sample

叉乘、快速排斥与跨立实验及求取三角形面积

<pre name="code" class="cpp">叉乘 (一)判断方向 (二)判断线段相交 (三)求三角形面积 (一)判断方向 叉乘的性质如下: (1). P x Q > 0; 表示P在Q的顺时针方向; (2). p x Q < 0; 表示P在Q的逆时针方向; (3). P x Q = 0; 表示P和Q是共线的 P(x1,y1),Q(x2,y2), P*Q=x1y2-x2y1 判断结果三种状态 模版为: struct point {

三角形面积

如图1所示.图中的所有小方格面积都是1. 那么,图中的三角形面积应该是多少呢? 请填写三角形的面积.不要填写任何多余内容或说明性文字.

三角形面积(海伦公式)

来自:http://www.oschina.net/code/snippet_149523_14180 描述 给你三个点,表示一个三角形的三个顶点,现你的任务是求出该三角形的面积 输入 每行是一组测试数据,有6个整数x1,y1,x2,y2,x3,y3分别表示三个点的横纵坐标.(坐标值都在0到10000之间)输入0 0 0 0 0 0表示输入结束测试数据不超过10000组 输出 输出这三个点所代表的三角形的面积,结果精确到小数点后1位(即使是整数也要输出一位小数位) 样例输入 0 0 1 1 1

rwkj 1363 正方形 长方形 三角形面积

C++:重载函数2(计算面积)时间限制(普通/Java):1000MS/3000MS 运行内存限制:65536KByte总提交:370 测试通过:241 描述 定义重载函数area(),分别计算正方形.长方形和三角形的面积. 输入 共计有3行. 第1行有一个实数,为正方形的边长: 第2行有二个实数,为长方形的两条边长: 第3行有三个实数,为三角形的三边长. 输出 正方形.长方形和三角形的面积(保留3位小数). 样例输入 3.54.2 5.623.0 4.0 5.0 样例输出 12.25023.6