热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

UVa11978福岛核爆问题:圆与多边形的交集面积计算及二分法应用

题目《UVa11978福岛核爆问题》涉及圆与多边形交集面积的计算及二分法的应用。该问题的核心在于通过精确的几何运算与高效的算法实现来解决复杂图形的面积计算。在实现过程中,特别需要注意的是对多边形顶点的平移处理,确保所有顶点包括最后一个顶点\(p[n]\)都经过正确的位移,以避免因细节疏忽导致的错误。此外,使用循环次数为50次的二分法能够有效提高算法的精度和稳定性。

题目地址:pdf版本

和上一个题目几乎是一模一样的,就不说思路了。

但是呢,这次是用for 50次写的二分,然后,容易wa的一点是,要把p[n] 也进行平移,漏掉了就wa了啊

代码:

#include
#include
#include
#include
#include
const  long double eps=1e-10;
const long double PI=acos(-1.0);

using namespace std;


struct Point{
    long double x;
    long double y;
    Point(long double x=0,long double y=0):x(x),y(y){}
    void operator<<(Point &A) {cout<eps)-(x<-eps); }
int sgn(long double x)  {return (x>eps)-(x<-eps); }
typedef  Point  Vector;

Vector  operator +(Vector A,Vector B) { return Vector(A.x+B.x,A.y+B.y);}

Vector  operator -(Vector A,Vector B) { return Vector(A.x-B.x,A.y-B.y); }

Vector  operator *(Vector A,long double p) { return Vector(A.x*p,A.y*p);  }

Vector  operator /(Vector A,long double p) {return Vector(A.x/p,A.y/p);}



ostream &operator<<(ostream & out,Point & P) { out<0)    return Length(v3);
    
    else return DistanceToLine(P, A, B);
    
}

Point GetLineProjection(Point P,Point A,Point B)
{
    Vector v=B-A;
    Vector v1=P-A;
    long double t=Dot(v,v1)/Dot(v,v);
    
    return  A+v*t;
}

bool  SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2)
{
    long double c1=Cross(b1-a1, a2-a1);
    long double c2=Cross(b2-a1, a2-a1);
    long double c3=Cross(a1-b1, b2-b1);
    long double c4=Cross(a2-b1, b2-b1);
    
    return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0 ;
    
}

bool  OnSegment(Point P,Point A,Point B)
{
    return dcmp(Cross(P-A, P-B))==0&&dcmp(Dot(P-A,P-B))<=0;
}

long double PolygonArea(Point *p,int n)
{
    long double area=0;
    
    for(int i=1;i &sol)
{
    long double a=L.v.x;
    long double b=L.p.x-C.c.x;
    long double c=L.v.y;
    long double d=L.p.y-C.c.y;
    
    long double e=a*a+c*c;
    long double f=2*(a*b+c*d);
    long double g=b*b+d*d-C.r*C.r;
    
    long double delta=f*f-4*e*g;
    
    if(dcmp(delta)<0) return 0;
    
    if(dcmp(delta)==0)
    {
        t1=t2=-f/(2*e);
        sol.push_back(L.point(t1));
        return 1;
    }
    
    else
    {
        t1=(-f-sqrt(delta))/(2*e);
        t2=(-f+sqrt(delta))/(2*e);
        
        sol.push_back(L.point(t1));
        sol.push_back(L.point(t2));
        
        return 2;
    }
    
}

// 向量极角公式

long double angle(Vector v)  {return atan2(v.y,v.x);}

int getCircleCircleIntersection(Circle C1,Circle C2,vector &sol)
{
    long double d=Length(C1.c-C2.c);
    
    if(dcmp(d)==0)
    {
        if(dcmp(C1.r-C2.r)==0)  return -1;  // 重合
        else return 0;    //  内含  0 个公共点
    }
    
    if(dcmp(C1.r+C2.r-d)<0)  return 0;  // 外离
    if(dcmp(fabs(C1.r-C2.r)-d)>0)  return 0;  // 内含
    
    long double a=angle(C2.c-C1.c);
    long double da=acos((C1.r*C1.r+d*d-C2.r*C2.r)/(2*C1.r*d));
    
    Point p1=C1.point(a-da);
    Point p2=C1.point(a+da);
    
    sol.push_back(p1);
    
    if(p1==p2)  return 1; // 相切
    else
    {
        sol.push_back(p2);
        return 2;
    }
}


//  求点到圆的切线

int getTangents(Point p,Circle C,Vector *v)
{
    Vector u=C.c-p;
    
    long double dist=Length(u);
    
    if(dcmp(dist-C.r)<0)  return 0;
    
    else if(dcmp(dist-C.r)==0)
    {
        v[0]=Rotate(u,PI/2);
        return 1;
    }
    
    else
    {
        
        long double ang=asin(C.r/dist);
        v[0]=Rotate(u,-ang);
        v[1]=Rotate(u,+ang);
        return 2;
    }
    
}

//  求两圆公切线


int getTangents(Circle A,Circle B,Point *a,Point *b)
{
    int cnt=0;
    
    if(A.r0)   // 外离   又有两条外公切线
    {
        long double  ang_in=acos(rsum/d);
        a[cnt]=A.point(base+ang_in);
        b[cnt]=B.point(base+ang_in+PI);
        cnt++;
        a[cnt]=A.point(base-ang_in);
        b[cnt]=B.point(base-ang_in+PI);
        cnt++;
    }
    
    return cnt;
}



Point Zero=Point(0,0);

long double  common_area(Circle C,Point A,Point B)
{
   // if(A==B)  return 0;
    if(A==C.c||B==C.c)  return 0;

    long double  OA=Length(A-C.c),OB=Length(B-C.c);
    long double  d=DistanceToLine(Zero, A, B);

    int sg=sgn(Cross(A,B));
    if(sg==0)  return 0;

    long double angle=Angle(A,B);

    if(dcmp(OA-C.r)<=0&&dcmp(OB-C.r)<=0)
    {
        return Cross(A,B)/2;

    }

    else if(dcmp(OA-C.r)>=0&&dcmp(OB-C.r)>=0&&dcmp(d-C.r)>=0)
    {
        return  sg*C.r*C.r*angle/2;

    }
    else if (dcmp(OA-C.r)>=0&&dcmp(OB-C.r)>=0&&dcmp(d-C.r)<0)
    {


        Point prj=GetLineProjection(Zero, A, B);

        if(OnSegment(prj, A, B))
        {
        vector p;
        Line L=Line(A,B-A);
        long double t1,t2;
        getLineCircleIntersection(L,C, t1, t2, p);

        long double s1=0;
        s1=C.r*C.r*angle/2;

        long double s2=0;
        s2=C.r*C.r*Angle(p[0],p[1])/2;
        s2-=fabs(Cross(p[0],p[1])/2);
        s1=s1-s2;

        return  sg*s1;
        }

        else
        {
            return sg*C.r*C.r*angle/2;
        }

    }
    else
    {
       
            if(dcmp(OB-C.r)<0)
            {
               
                Point temp=A;
                A=B;
                B=temp;
            }

         Point inter_point;
        
            long double t1,t2;
            Line L=Line(A,B-A);
            vector inter;
            getLineCircleIntersection(L, C, t1, t2,inter);
        
                    if(OnSegment(inter[0], A, B))
                inter_point=inter[0];
            else
            {
                inter_point=inter[1];

            }

        
//        两种方法求交点都可以
//        Point  prj=GetLineProjection(Zero, A, B);
//        
//        Vector v=B-A;
//        v=v/Length(v);
//        long long double mov=sqrt(C.r*C.r-d*d);
//        
//        if(OnSegment(prj+v*mov, A, B))
//        {
//            inter_point=prj+v*mov;
//        }
//        else
//        {
//            inter_point=prj+Vector(-v.x,-v.y)*mov;
//        }
        
        
            long double s=fabs(Cross(inter_point, A)/2);
            s+=C.r*C.r*Angle(inter_point,B)/2;

            return s*sg;


    }
}

Point p[5500];

int main()
{
    int n;
    Circle C;
    int index=0;
    int T;
    cin>>T;
    long  double  P;
    while(cin>>n)
    {
        for(int i=0;i>P;
        
        
        for(int i=0;i<=n;i++)   // wa!
            p[i]=p[i]-C.c;
        
    
        
        
        C.c=Zero;
        
       
    
        long double l=0,r=1e4;
        long double mid=l;
        
        for(int tim=0;tim<50;tim++)
        {
            mid=l+(r-l)/2;
            
            C.r=mid;
            
            long double ans=0;
        
           for(int i=0;i=area*P/100.0)  r=mid;
            else l=mid;
        }
        
       // if(mid-floor(mid)>0.5) mid+=1;
        printf("Case %d: %.0Lf\n",++index,mid);
        
        
    }

}



推荐阅读
  • 火星商店问题:线段树分治与持久化Trie树的应用
    本题涉及编号为1至n的火星商店,每个商店有一个永久商品价值v。操作包括每天在指定商店增加一个新商品,以及查询某段时间内某些商店中所有商品(含永久商品)与给定密码值的最大异或结果。通过线段树分治和持久化Trie树来高效解决此问题。 ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
  • 本文详细探讨了VxWorks操作系统中双向链表和环形缓冲区的实现原理及使用方法,通过具体示例代码加深理解。 ... [详细]
  • Codeforces Round #566 (Div. 2) A~F个人题解
    Dashboard-CodeforcesRound#566(Div.2)-CodeforcesA.FillingShapes题意:给你一个的表格,你 ... [详细]
  • 本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ... [详细]
  • C++: 实现基于类的四面体体积计算
    本文介绍如何使用C++编程语言,通过定义类和方法来计算由四个三维坐标点构成的四面体体积。文中详细解释了四面体体积的数学公式,并提供了两种不同的实现方式。 ... [详细]
  • 本文探讨了如何在模运算下高效计算组合数C(n, m),并详细介绍了乘法逆元的应用。通过扩展欧几里得算法求解乘法逆元,从而实现除法取余的计算。 ... [详细]
  • 本实验主要探讨了二叉排序树(BST)的基本操作,包括创建、查找和删除节点。通过具体实例和代码实现,详细介绍了如何使用递归和非递归方法进行关键字查找,并展示了删除特定节点后的树结构变化。 ... [详细]
  • 本文详细介绍了C语言中链表的两种动态创建方法——头插法和尾插法,包括具体的实现代码和运行示例。通过这些内容,读者可以更好地理解和掌握链表的基本操作。 ... [详细]
  • 本题涉及一棵由N个节点组成的树(共有N-1条边),初始时所有节点均为白色。题目要求处理两种操作:一是改变某个节点的颜色(从白变黑或从黑变白);二是查询从根节点到指定节点路径上的第一个黑色节点,若无则输出-1。 ... [详细]
  • Linux设备驱动程序:异步时间操作与调度机制
    本文介绍了Linux内核中的几种异步延迟操作方法,包括内核定时器、tasklet机制和工作队列。这些机制允许在未来的某个时间点执行任务,而无需阻塞当前线程,从而提高系统的响应性和效率。 ... [详细]
  • 本题探讨如何通过最大流算法解决农场排水系统的设计问题。题目要求计算从水源点到汇合点的最大水流速率,使用经典的EK(Edmonds-Karp)和Dinic算法进行求解。 ... [详细]
author-avatar
mobiledu2502927397
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有