hdu6354 /// 圆的相交
题目大意:
给定m r 初始圆盘以原点为圆心半径为r
给定m个圆的圆心(x,y) 半径r 保证m个圆互不相交且不会覆盖圆盘
用这m个圆来切割初始的圆盘求最后圆盘外围的长度
求圆与圆盘的交点
减去圆盘上两点间的周长 加上圆上两点间的周长 判断一下方向
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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\n",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\n",ans); } return 0; }
也可以用余弦定理 https://www.cnblogs.com/Dillonh/p/9433714.html
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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\n",ans); } return 0; }