BZOJ 1043: [HAOI2008]下落的圓盤 計算幾何,貪心,線段交
Description
有n個圓盤從天而降,後面落下的可以蓋住前面的。求最後形成的封閉區域的周長。看下面這副圖, 所有的紅
色線條的總長度即為所求.
Input
第一行為1個整數n,N<=1000
接下來n行每行3個實數,ri,xi,yi,表示下落時第i個圓盤的半徑和圓心座標.
Output
最後的周長,保留三位小數
Sample Input
2
1 0 0
1 1 0
Sample Output
10.472
解題方法:看到題目成mengbier了。這個不是圓的周長交吧。。確實不是。。可是不會啊。。看了題解,感覺這個題其實很傻叉。。對於每一個圓i,求出這個圓盤會被後面的每一個圓盤覆蓋哪一段。對於一個圓,可以用-pi到pi的弧度表示區間,然後就可以用線段覆蓋的方法求出區間被覆蓋了多少了。 因此關鍵是對於兩個圓盤i,j,如何求出i被覆蓋的區間。首先對於兩個圓的圓心x,y,可以求出向量(y-x)的atan2值,相當於與x軸正方向的夾角α,範圍-pi到pi。然後根據餘弦定理cos∠A=(b^2+c^2-a^2)/2bc,得到x的圓心到兩圓的一個焦點的射線關於兩圓連心線旋轉角的餘弦,然後用acos得到旋轉角β,那麼α±β就是對應的區間。注意邊界問題,如果下界<-pi,就變成下界+2pi->pi,上界>pi同理。還有要判斷圓相離的情況。。網上的題解看到這個題沒卡精度。所以就沒設eps了。。*一定要好好學習計幾了(騙你的,我才不會)*
程式碼如下:
#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1.0);
const int N = 2005;
int n, cnt;
struct Point{
double x, y;
Point(){}
Point(double x, double y) : x(x), y(y) {}
bool operator <(const Point &rhs) const{
return x < rhs.x;
}
}s[N];
struct Circle{
Point o;
double r;
}a[N];
double sqr(double x){
return x*x;
}
double getdis(Point a, Point b){
return sqrt(sqr(b.x - a.x) + sqr(b.y - a.y));
}
void ins(double x, double y){
s[++cnt] = Point(x, y);
}
void getsegment(Circle u, Circle v, double dis){
double t1 = atan2(v.o.y - u.o.y, v.o.x - u.o.x);
double t2 = acos((sqr(dis) + sqr(u.r) - sqr(v.r)) / (2*dis*u.r));
Point t; t.x = t1 - t2; t.y = t1 + t2;
if(t.x >= -pi && t.y <= pi) ins(t.x, t.y);
else if(t.x < -pi){
ins(t.x + 2*pi, pi);
ins(-pi, t.y);
}else{
ins(t.x, pi);
ins(-pi, t.y - 2*pi);
}
}
double cal(){
double ans = 0;
double l = -10, r = -10;
sort(s + 1, s + cnt + 1);
for(int i = 1; i <= cnt; i++){
if(s[i].x > r){
ans += r - l;
l = s[i].x;
r = s[i].y;
}
else{
r = max(r, s[i].y);
}
}
ans += (r - l);
return 2*pi - ans;
}
int main(){
double ans = 0;
scanf("%d", &n);
for(int i = n; i >= 1; i--) scanf("%lf%lf%lf", &a[i].r, &a[i].o.x, &a[i].o.y);
for(int i = 1; i <= n; i++){
cnt = 0;
int j;
for(j = 1; j < i; j++){
double tmp = getdis(a[i].o, a[j].o);
if(a[j].r - a[i].r > tmp) break;
if(a[j].r + a[i].r > tmp && fabs(a[j].r - a[i].r) < tmp){
getsegment(a[i], a[j], tmp);
}
}
if(j == i) ans += a[i].r * cal();
}
printf("%.3f\n", ans);
return 0;
}
相關文章
- 【計算幾何】線段相交
- POJ 1039-Pipe(計算幾何-線段相交、求交點)
- 三維幾何生成:多段線、圓弧
- POJ 2991 Crane(線段樹+計算幾何)
- HDU 4643 GSM(計算幾何求線段的中垂線)
- 【計算幾何】求線段相交交點座標
- POJ 1127-Jack Straws(計算幾何 線段相交)
- BZOJ 1027 合金 計算幾何,Floyd判環
- Luogu P4425 轉盤 題解 [ 黑 ] [ 線段樹 ] [ 貪心 ] [ 遞迴 ]遞迴
- 計算幾何
- 【計算幾何】點定位(線段,三角形,多邊形)
- 【第一道計算幾何題】 UVA11178 Morley‘s Theorem (二維幾何,旋轉直線求求交點)REM
- 計算幾何:模板
- 計算幾何模板
- L3-012 水果忍者 (30分):貪心,幾何
- [計算幾何]圓與三角形是否相交
- BZOJ 1007 HNOI 2008 水平可見直線 計算幾何+棧
- 計算兩條直線的交點
- [筆記] 計算幾何筆記
- POJ 1584-A Round Peg in a Ground Hole(計算幾何-凸包、點到線段距離)
- ut.cpp 最大線段並減線段交 [線段樹]
- 計算幾何_向量的實現
- 【計算幾何】向量表示
- 【總結】計算幾何模板
- 二維計算幾何模板
- 三維計算幾何模板
- Something about 計算幾何
- 計算幾何常用的函式/方法函式
- poj 2010 Moo University - Financial Aid (貪心+線段樹)NaNAI
- 貪心演算法-找不重疊的區間段演算法
- 計算幾何 —— 二維幾何基礎 —— 距離度量方法
- 邊緣計算、霧計算、雲端計算區別幾何?
- BZOJ5177 : [Jsoi2013]貪心的導遊JS
- 【學習筆記】計算幾何筆記
- 【計算幾何】多邊形交集
- 計算幾何——平面最近點對
- 幾種計算圓周率的軟體比較
- 橢圓曲線加法原理計算