1. 程式人生 > >HDU 6158 計算幾何 笛卡爾定理 + 韋達定理

HDU 6158 計算幾何 笛卡爾定理 + 韋達定理

題目連結

題解已經講得非常清楚了,補充一點細節吧。

(1).關於笛卡爾定理

對於此題,只需要瞭解這麼一個性質:(來自wiki 用的谷歌翻譯,若有偏差還請指出~)

定義一個圓的曲率k=±1r,其中r是其半徑。
若平面有兩兩相切,且有6個獨立切點的四個圓,設其曲率為k1,k2,k3,k4(若該圓與其他圓均外切,則曲率取正,否則取負)則其滿足性質:

(k1+k2+k3+k4)2=2(k21+k22+k23+k24)

(2).關於韋達定理
對於此題,第一個與已知圓相切的圓的半徑非常好求,其半徑r3=(r1r2),其中r1是已知圓中較大圓的半徑。

故我們現在k1,k2,k3均為已知,代入上面笛卡爾定理的式子便能求解出k

4
易發現這是一個關於k4的二次方程,化簡為標準形式為:

k242(k1+k2+k3)k4+(k1+k2+k3)22(k21+k22+k23)=0

直接求解是挺困難的,設兩個解是x1,x2,利用韋達定理:

x1+x2=2(k1+k2+k3)

因為k4所代表的圓與前三個圓均相切,對於此題,x1,x2就是k3所代表圓左右兩個圓的曲率。

對於題目給的圖:
k3代表圓1,則x1,x2分別代表圓2和圓3
k3代表圓2,則x1,x2分別代表圓1和圓4

這樣我們就可以類似迭代的方式,不斷往後遞推求解。

這裡寫圖片描述

另外小心精度和時間的問題。
因為N越大,其後面的圓的面積對於答案的貢獻幾乎可以忽略不計,這時要及時退出迴圈,避免超時。

親測,當eps取(1e-13)時跑得最快。

218msAC
程式碼:

#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;

const double eps = 1e-13;
const double PI = acos(-1.0);
int main(){
    int T;scanf("%d",&T);
    while(T--){
        int r1,r2,n;
        scanf
("%d%d%d",&r1,&r2,&n); if(r1 < r2) swap(r1,r2); double k1 = -1.0/r1,k2 = 1.0/r2,k3 = 1.0/(r1-r2); double k4 = k1 + k2 + k3; double ans = (r1-r2)*(r1-r2); n--; for(int i=1 ;i<=n ;i+=2){ double r4 = 1.0/k4; if(r4*r4 < eps) break; ans += r4*r4;if(i+1<=n) ans += r4*r4; double k5 = 2*(k1+k2+k4) - k3; k3 = k4;k4 = k5; } printf("%.5f\n",ans*PI); } return 0; }