hdu6354 Everything Has Changed (圓的相交弧長)
阿新 • • 發佈:2019-02-19
closed clear pre 多少 方法 queue 圓心 space r+
題目傳送門
題意:
用一堆圓來切割一個圓心為原點,半徑為R的圓A,問切割完畢後圓A外圍剩余部分的周長(圖中的紅線部分)。
思路:
首先判定圓與圓A的關系,這題我們只需要與A內切、相交的圓。
然後就是求每個圓把圓A切割掉多少周長,增加了多少周長(因為圓A被切割的部分在切割後絕對是內凹的,此時周長是增加的),
內切的時候直接加上切割圓的周長(如最上面的那個小圓),
相交的圓部分我采用的方法是用余弦定理
(A的半徑記為R,切割圓半徑為r,二者的圓心距離為d,圓心的連線與 圓A和一個交點的夾角為a,則2*d*R*cosa=R*R+d*d-r*r)
求出夾角a,再用弧長公式l=a*r求出弧長最後進行加減即可。
來自博客:https://www.cnblogs.com/Dillonh/p/9433714.html
代碼:
#include <set> #include <map> #include <queue> #include <stack> #include <cmath> #include <bitset> #include <cstdio> #include <string> #include <vector> #include <cstdlib> #includeView Code<cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; typedef pair<ll, ll> pll; typedef pair<ll, int> pli; typedef pair<int, ll> pil;; typedef pair<int, int> pii; typedef unsigned long long ull; #define lson i<<1 #definerson i<<1|1 #define bug printf("*********\n"); #define FIN freopen("D://code//in.txt", "r", stdin); #define debug(x) cout<<"["<<x<<"]" <<endl; #define IO ios::sync_with_stdio(false),cin.tie(0); const double eps = 1e-8; const int mod = 10007; const int maxn = 1e6 + 7; const double pi = acos(-1); const int inf = 0x3f3f3f3f; const ll INF = 0x3f3f3f3f3f3f3f; typedef struct stu { double x,y; } point; double Distance(point a,point b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } double Inter(point a,double R,point b,double r) { //變化的周長 double dis=Distance(a,b); double angle1=acos((R*R+dis*dis-r*r)/(2.0*R*dis)); double angle2=acos((r*r+dis*dis-R*R)/(2.0*r*dis)); double s=r*angle2*2-R*angle1*2; return s; } int t, m, R; double x, y, r, ans; stu o, p; int main() { //FIN; scanf("%d", &t); while(t--) { scanf("%d%d", &m, &R); ans = 2 * pi * R; o.x = 0, o.y = 0; for(int i = 1; i <= m; i++) { scanf("%lf%lf%lf", &x, &y, &r); p.x = x, p.y = y; double d = Distance(o, p); if(d - R - r >= eps) continue; //外離 if(fabs(R - r) - d > eps) continue; //內離 if(R == r + d) { //內切 ans += 2 * pi * r; } else { //相交 ans += Inter(o, R, p, r); } } printf("%.12f\n", ans); } return 0; }
還有另外一個代碼:
#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; }View Code
hdu6354 Everything Has Changed (圓的相交弧長)