POJ 2451 求半面交

题意:求半面想交后的面积,题目数据较大,使用o(n*logn)算法。

这题WA两次忘了m<3的情况,不应该啊= = 。

#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int mm=20005;
typedef double DIY;
struct point
{
    DIY x,y;
    point() {}
    point(DIY _x,DIY _y):x(_x),y(_y) {}
} g[mm];
double Direction(point pi,point pj,point pk) //判断向量PiPj在向量PiPk的顺逆时针方向 +顺-逆0共线
{
    return (pj.x-pi.x)*(pk.y-pi.y)-(pk.x-pi.x)*(pj.y-pi.y);
}
point MakeVector(point &P,point &Q)
{
    return point(Q.x-P.x,Q.y-P.y);
}
DIY CrossProduct(point P,point Q)
{
    return P.x*Q.y-P.y*Q.x;
}
DIY MultiCross(point P,point Q,point R)
{
    return CrossProduct(MakeVector(Q,P),MakeVector(Q,R));
}
struct halfPlane
{
    point s,t;
    double angle;
    halfPlane() {}
    halfPlane(point _s,point _t):s(_s),t(_t) {}
    halfPlane(DIY sx,DIY sy,DIY tx,DIY ty):s(sx,sy),t(tx,ty) {}
    void GetAngle()
    {
        angle=atan2(t.y-s.y,t.x-s.x);
    }
} hp[mm],q[mm];
point IntersectPoint(halfPlane P,halfPlane Q)
{
    DIY a1=CrossProduct(MakeVector(P.s,Q.t),MakeVector(P.s,Q.s));
    DIY a2=CrossProduct(MakeVector(P.t,Q.s),MakeVector(P.t,Q.t));
    return point((P.s.x*a2+P.t.x*a1)/(a2+a1),(P.s.y*a2+P.t.y*a1)/(a2+a1));
}
bool cmp(halfPlane P,halfPlane Q)
{
    if(fabs(P.angle-Q.angle)<1e-8)
        return MultiCross(P.s,P.t,Q.s)>0;
    return P.angle<Q.angle;
}
bool IsParallel(halfPlane P,halfPlane Q)
{
    return fabs(CrossProduct(MakeVector(P.s,P.t),MakeVector(Q.s,Q.t)))<1e-8;
}
void HalfPlaneIntersect(int n,int &m)
{
    sort(hp,hp+n,cmp);
    int i,l=0,r=1;
    for(m=i=1; i<n; ++i)
        if(hp[i].angle-hp[i-1].angle>1e-8)hp[m++]=hp[i];
    n=m;
    m=0;
    q[0]=hp[0],q[1]=hp[1];
    for(i=2; i<n; ++i)
    {
        if(IsParallel(q[r],q[r-1])||IsParallel(q[l],q[l+1]))return;
        while(l<r&&MultiCross(hp[i].s,hp[i].t,IntersectPoint(q[r],q[r-1]))>0)--r;
        while(l<r&&MultiCross(hp[i].s,hp[i].t,IntersectPoint(q[l],q[l+1]))>0)++l;
        q[++r]=hp[i];
    }
    while(l<r&&MultiCross(q[l].s,q[l].t,IntersectPoint(q[r],q[r-1]))>0)--r;
    while(l<r&&MultiCross(q[r].s,q[r].t,IntersectPoint(q[l],q[l+1]))>0)++l;
    q[++r]=q[l];
    for(i=l; i<r; ++i)
        g[m++]=IntersectPoint(q[i],q[i+1]);
}
int main()
{
    int n,m;
    point a,b;
    point p[5];
    p[0].x=0,p[0].y=0;
    p[1].x=10000,p[1].y=0;
    p[2].x=10000,p[2].y=10000;
    p[3].x=0,p[3].y=10000;
    while(~scanf("%d",&n))
    {
        for(int i=0; i<n; i++)
        {
            scanf("%lf%lf%lf%lf",&a.x,&a.y,&b.x,&b.y);
            hp[i]=halfPlane(a,b);
            hp[i].GetAngle();
        }
        for(int i=0; i<4; i++)
        {
            hp[n+i]=halfPlane(p[i],p[(i+1)%4]);
            hp[i+n].GetAngle();
        }
        HalfPlaneIntersect(n+4,m);
        if(m<3)
        {
            puts("0.0");
            continue;
        }
        double ans=0;
        for(int i=0; i<m; i++)
            ans+=Direction(g[i],g[(i+1)%m],p[0]);
        ans=ans<0?-ans/2:ans/2;
        printf("%.1f\n",ans);
    }
    return 0;
}
时间: 2024-08-01 15:42:09

POJ 2451 求半面交的相关文章

POJ 3525 二分+半面相交

题意:给定一个凸多边形问能包裹圆的最大半径. 将每条边向内移动距离d,知道半面相交的内核不存在,确定最大的d并且达到精度就可以了. #include<cmath> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int mm=111; typedef double DIY; struct point { DIY x,y; point() {}

POJ 3407 求球面距离

题意:给出球面上两点的经纬度,注意分跟秒进制是60进制的,让求球面上的两点距离. 有公式  r*acos(sin(a1)*sin(a2)+cos(a1)*cos(a2)*cos(b1-b2)) . #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; double Dis3D(d

POJ 1329 求三角形外接圆

题意给出三角形三点坐标让求出该三角形的外接圆标准方程和一般方程. 这题输出很恶心,注意0.000的时候要输出并且前面的符号为" + ",那么外接圆的半径r通过S=(a*b*c)/(4*r)可以求出r=(a*b*c)/(4*S),然后外心坐标是三边垂直平分线的交点,求出两个垂直平分线方程然后可以得出交点坐标. #include <iostream> #include<cstdio> #include<cstring> #include<algor

POJ 3348 求凸包面积

题意给出n个点求凸包,然后求出凸包面积就可以. 模板题求出凸包后用叉积求出面积就可以了. #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef int PointType; struct point { PointType x,y; int num; }; poi

POJ 1269 求两直线交点

题意:给出4个点,两个一组在两条直线上,求出这两条直线的重合部分,NONE就是平行,LINE就是重合,POINT就是有交点并且输出交点. 解析几何那么求,没什么好说的直接看代码吧. #include <iostream> #include<cstdio> #include<algorithm> using namespace std; typedef double PointType; struct point { PointType x,y; }; point jd;

POJ 2354 求球面两点距离

题意:给出球面上两点经纬度,计算球面两点距离.输入输出比较恶心. 公式题 直接上公式就能A. #include<cmath> #include<cstdio> #include<iostream> using namespace std; double a1,b1,a2,b2,d,r=6875/2.0; char s[99]; double Dis3D(double a1,double b1,double a2,double b2) { return r*acos(si

POJ 3335 半面相交

题意:给你一个多边形,问是否存在区域能看到多边形的任意位置,也就是存不存在内核. 将每条边看做一个半面求半面相交.如果存在那么半面至少三个. #include<cmath> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int mm=111; typedef double DIY; struct point { DIY x,y; point

HDU 4316 凸包+半面相交

题意:一个房间,在房间顶部有三个摄像头,房间有放有一个凸多面体的机器,问这个机器对摄像头在地面造成盲点的面积.房间顶部z=100,地面z=0. 首先根据空间直线方程(x-x1)/(x1-x2)=(y-y1)/(y1-y2)=(z-z1)/(z1-z2) 求出每个摄像头与凸多面体连线与地面(z=0)的交点.在对这个摄像头在地面的交点求凸包,这个区域就个该摄像头盲区的面积,但是需要求三个盲区面积的交,所以把3个凸包的边变成半面,求最后的半面交,得出相交的多边形再求面积即为答案.上来就是甩模板啊..

电子印章 椭圆印章-请教生成椭圆印章的算法

问题描述 请教生成椭圆印章的算法 要生成一个椭圆形印章,类似于下面这个图片,要求是"中国xxxx股份有限公司"旋转文字所占的角度可以是0~360度的任意角度,文字要根据旋转字所占的角度均匀排列,各位大神给点思路,谢谢了 解决方案 看"国"字是个矩形而不是梯形,说明只是把字体转了一个角度而已. 先求半个椭圆的周长L,图中是12个字占半边弧,每个字占有的弧长 l=L/24. 从左边开始向右上积分算弧长,在 0.5*L.1.5*l.2.5*l--处求切线,切线的角度就是输