hdu6354 /// 圆的相交

Posted zquzjx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu6354 /// 圆的相交相关的知识,希望对你有一定的参考价值。

题目大意:

给定m r 初始圆盘以原点为圆心半径为r

给定m个圆的圆心(x,y) 半径r 保证m个圆互不相交且不会覆盖圆盘

用这m个圆来切割初始的圆盘求最后圆盘外围的长度

 

求圆与圆盘的交点

减去圆盘上两点间的周长 加上圆上两点间的周长 判断一下方向

技术分享图片
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long
#define PI acos(-1)
#define pb(a) push_back(a)
#define mem(i,j) memset(i,j,sizeof(i))
const int N=1e5+5;
const int MOD=1e9+7;
const double eps=1e-8;

double add(double a,double b) {
    if(abs(a+b)<eps*(abs(a)+abs(b))) return 0;
    return a+b;
}
int dcmp(double x) {
    if(abs(x)<eps) return 0;
    else return x<0 ? -1:1;
}
struct P {
    double x,y;
    P(){} P(double _x,double _y):x(_x),y(_y){}
    P operator - (P p) { return P(add(x,-p.x),add(y,-p.y)); }
    P operator + (P p) { return P(add(x,p.x),add(y,p.y)); }
    P operator * (double d) { return P(x*d,y*d); }
    P operator / (double d) { return P(x/d,y/d); }
    double dot (P p) { return add(x*p.x,y*p.y); }
    double det (P p) { return add(x*p.y,-y*p.x); }
    bool operator == (const P& p)const {
        return abs(x-p.x)<eps && abs(y-p.y)<eps; }
    bool operator < (const P& p)const {
        return x<p.x || (x==p.x && y<p.y); }
};
struct L {
    P p, v; double ang;
    L(){} L(P _p,P _v):p(_p),v(_v){ ang=atan2(v.y,v.x); }
    P acP(double t) { return p+v*t; }
};
struct C {
    P p; double r;
    C(){} C(P _p,double _r):p(_p),r(_r){}
    P acP(double a) { return P(p.x+cos(a)*r,p.y+sin(a)*r); }
    double AL(double ang) { return ang*r; }
}c;
// 求向量a的长度
double lenP(P a) { return sqrt(a.dot(a)); }
// 求向量v极角
double angle(P v) { return atan2(v.y,v.x); }
// 求两向量夹角
double Angle(P u,P v) { return acos(u.dot(v)/lenP(u)/lenP(v));}
/* 判断两圆相交
求圆c1与c2的交点 并用s保存交点
w记录是外切1还是内切-1
*/
int insCC(C c1,C c2,vector<P>& s,int* w) {
    double d=lenP(c1.p-c2.p);
    if(abs(d)<eps) {
        if(abs(c1.r-c2.r)<eps) return -1; // 重合
        return 0; // 内含
    }
    if((c1.r+c2.r-d)<-eps) return 0; // 外离
    if(d-abs(c1.r-c2.r)<-eps) return 0; // 内离

    (*w)=dcmp(d-c1.r);
    double ang=angle(c2.p-c1.p); // 向量c1c2求极角
    double da=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    // c1与交点的向量 与 c1c2 的夹角
    P p1=c1.acP(ang-da), p2=c1.acP(ang+da); // 求得两交点

    s.pb(p1);
    if(p1==p2) return 1; // 同一个点
    s.pb(p2); return 2;
}

int main()
{
    int t; scanf("%d",&t);
    while(t--) {
        int m; double r;
        scanf("%d%lf",&m,&r);
        c.p.x=c.p.y=0, c.r=r;
        double ans=2.0*PI*c.r;
        while(m--) {
            //printf("%lf
",ans);
            C t; scanf("%lf%lf%lf",&t.p.x,&t.p.y,&t.r);
            vector <P> p; p.clear();
            int w, s=insCC(c,t,p,&w);
            if(s==1) {
                if(w==-1) ans+=2.0*PI*t.r;
            } else if(s==2) {
                P u=p[0], v=p[1];
                double ang=Angle(u,v);
                if(dcmp(u.det(v))<0) ang=2.0*PI-ang;
                ans-=c.AL(ang); /// 减去圆盘被切的部分周长
                u=p[0]-t.p, v=p[1]-t.p;
                ang=Angle(u,v);
                if(dcmp(u.det(v))>0) ang=2.0*PI-ang;
                ans+=t.AL(ang); /// 加上切割产生的新边缘
            }
        }
        printf("%.10f
",ans);
    }

    return 0;
}
View Code

 

也可以用余弦定理 https://www.cnblogs.com/Dillonh/p/9433714.html

技术分享图片
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long
#define PI acos(-1)
#define pb(a) push_back(a)
#define mem(i,j) memset(i,j,sizeof(i))
const int N=1e5+5;
const int MOD=1e9+7;
const double eps=1e-8;

double add(double a,double b) {
    if(abs(a+b)<eps*(abs(a)+abs(b))) return 0;
    return a+b;
}
int dcmp(double x) {
    if(abs(x)<eps) return 0;
    else return x<0 ? -1:1;
}
struct P {
    double x,y;
    P(){} P(double _x,double _y):x(_x),y(_y){}
    P operator - (P p) { return P(add(x,-p.x),add(y,-p.y)); }
    P operator + (P p) { return P(add(x,p.x),add(y,p.y)); }
    P operator * (double d) { return P(x*d,y*d); }
    P operator / (double d) { return P(x/d,y/d); }
    double dot (P p) { return add(x*p.x,y*p.y); }
    double det (P p) { return add(x*p.y,-y*p.x); }
    bool operator == (const P& p)const {
        return abs(x-p.x)<eps && abs(y-p.y)<eps; }
    bool operator < (const P& p)const {
        return x<p.x || (x==p.x && y<p.y); }
};
struct C {
    P p; double r;
    C(){} C(P _p,double _r):p(_p),r(_r){}
    P acP(double a) { return P(p.x+cos(a)*r,p.y+sin(a)*r); }
    double AL(double ang) { return ang*r; }
}c;
// 求向量a的长度
double lenP(P a) { return sqrt(a.dot(a)); }
double change(C t) {
    double D=lenP(t.p);
    if(dcmp(c.r-t.r-D)>0) return 0; // 内离
    if(dcmp(c.r-t.r-D)==0) return 2.0*PI*t.r; // 内切
    if(dcmp(c.r+t.r-D)<=0) return 0; // 外离 外切
    double angc=acos((c.r*c.r+D*D-t.r*t.r)/(2.0*c.r*D));
    double angt=acos((t.r*t.r+D*D-c.r*c.r)/(2.0*t.r*D));
    return t.AL(angt*2.0)-c.AL(angc*2.0);
}

int main()
{
    int t; scanf("%d",&t);
    while(t--) {
        int m; double r;
        scanf("%d%lf",&m,&r);
        c.p.x=c.p.y=0, c.r=r;
        double ans=2.0*PI*c.r;
        while(m--) {
            C t; scanf("%lf%lf%lf",&t.p.x,&t.p.y,&t.r);
            ans+=change(t);
        }
        printf("%.10f
",ans);
    }

    return 0;
}
View Code

 

以上是关于hdu6354 /// 圆的相交的主要内容,如果未能解决你的问题,请参考以下文章

hdu 6354 Everything Has Changed

Everything Has Changed(HDU6354+圆交+求周长)

[hdu 3264] Open-air shopping malls(二分+两圆相交面积)

HDU 5531

HDOJ6354Everything Has Changed(计算几何)

hdu-5127------hdu5137