[HDU](6354)Everything Has Changed ---- 餘弦定理+計算幾何
阿新 • • 發佈:2019-02-03
題意:就是讓你求圖中紅色邊的長度,不會出現切割面積覆蓋原零件面積和兩個切割面積交叉的情況。
做法:一開始直接用兩圓相交求交點的幾何模板構造了演算法,沒想到WA到哭QAQ
到最後看了杜教的B站講解才知道自己好懵逼,直接饒了原路,知道三邊是可以用餘弦定理的啊!!
這樣的話就不用板子了,估計自己一直wa,是計算太多,導致精度缺失了吧……
做法的話,內切和外切、相離就不用說啦
就說說相交:我們把圓心為(0,0)的圓稱為大圓,半徑為R,其他稱為小圓,半徑為r
一、兩圓心的直線與R的夾角 (a2/2)為銳角時
我們可以用餘弦定理,求得角a2/2,以及角a1/2,這樣就可求出弧長c2,c1
用大圓的周長l1 所求的邊長= l1-c1+c2
二、兩圓心的直線與R的夾角 (a2/2)為鈍角時
我們可以用餘弦定理,求得角a2,以及角a1/2,這時我們相求弧長c2(即小圓對應的弧長),就應該是用角度π-a2
這樣用角a1和2*(π-a2)就可以求弧長c1,c2
大圓的周長l1,小圓的周長l2,所求的邊長 = l - c1 + (l2-c2)
以上~
AC程式碼:
#include<bits/stdc++.h> using namespace std; const double PI = 4*atan2(1.0,1.0); struct PPoint { double x,y; }; double len(double x1,double y1,double x2,double y2) { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } struct Circle { double x,y,r; }; int main() { #ifdef LOCAL_FILE freopen("in.txt","r",stdin); #endif // LOCAL_FILE int t; scanf("%d",&t); while(t--) { Circle cc[105]; double R; int m; scanf("%d %lf",&m,&R); for(int i=0;i<m;i++) scanf("%lf %lf %lf",&cc[i].x,&cc[i].y,&cc[i].r); double cir1 = 2*PI*R; double ans = cir1; for(int i=0;i<m;i++) { double d1 = len(cc[i].x,cc[i].y,0,0); double cir2 = 2*PI*cc[i].r; if(d1+cc[i].r == R) { ans+=cir2; } else if(d1 == cc[i].r+R) continue; else if(d1+cc[i].r<R) continue; else { double a1 = acos((R*R+d1*d1-cc[i].r*cc[i].r)/(2*d1*R)); double a2 = acos((cc[i].r*cc[i].r+d1*d1-R*R)/(2*d1*cc[i].r)); double c1 = 2*a1*R; double c2; if(a2<=PI/2) { c2 = 2*a2*cc[i].r; ans+=c2; ans-=c1; } else if(a2>PI/2) { a2 = PI-a2; c2 = 2*a2*cc[i].r; ans = ans+(cir2-c2); ans-=c1; } } } printf("%.20f\n",ans); } return 0; }