1. 程式人生 > >[HDU](6354)Everything Has Changed ---- 餘弦定理+計算幾何

[HDU](6354)Everything Has Changed ---- 餘弦定理+計算幾何

題目連結

題意:就是讓你求圖中紅色邊的長度,不會出現切割面積覆蓋原零件面積和兩個切割面積交叉的情況。

做法:一開始直接用兩圓相交求交點的幾何模板構造了演算法,沒想到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;
}