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;
}
相關文章
- 三維幾何生成:多段線、圓弧
- BZOJ5249: [2018多省省隊聯測]IIIDX(線段樹 貪心)
- [貪心]最大線段重疊
- Luogu P4425 轉盤 題解 [ 黑 ] [ 線段樹 ] [ 貪心 ] [ 遞迴 ]遞迴
- bzoj2697: 特技飛行(貪心)
- bzoj2151: 種樹(貪心+堆)
- L3-012 水果忍者 (30分):貪心,幾何
- 計算幾何
- BZOJ5068: 友好的生物(狀壓 貪心)
- 【第一道計算幾何題】 UVA11178 Morley‘s Theorem (二維幾何,旋轉直線求求交點)REM
- bzoj3709: [PA2014]Bohater(貪心)
- BZOJ5177 : [Jsoi2013]貪心的導遊JS
- 計算幾何:模板
- 計算幾何模板
- [計算幾何]圓與三角形是否相交
- bzoj4029: [HEOI2015]定價(貪心)
- Something about 計算幾何
- [筆記] 計算幾何筆記
- bzoj1086: [SCOI2005]王室聯邦(貪心)
- bzoj5177: [Jsoi2013]貪心的導遊(主席樹)JS
- bzoj2426: [HAOI2010]工廠選址(貪心)
- 計算兩條直線的交點
- 計算幾何 —— 二維幾何基礎 —— 距離度量方法
- SGU 124 Broken line(計算幾何)
- 計算幾何——平面最近點對
- POJ - 1556 【計算幾何 + 最短路】
- 【學習筆記】計算幾何筆記
- ut.cpp 最大線段並減線段交 [線段樹]
- 貪心演算法-找不重疊的區間段演算法
- bzoj1054: [HAOI2008]移動玩具(寬搜)
- 邊緣計算、霧計算、雲端計算區別幾何?
- 洛谷P3586 [POI2015]LOG(貪心 權值線段樹)
- bzoj1150: [CTSC2007]資料備份Backup(堆+貪心)
- BNUOJ 12887 isumi(計算幾何+最大流)
- SGU 120 SGU 228 Archipelago(計算幾何)Go
- Codeforces 1070C - Cloud Computing 思路+線段樹+貪心 (2018-2019 ICPC, NEERC)Cloud
- 橢圓曲線加法原理計算
- 貪心
- Python中OpenCV劃線、畫圓、橢圓、新增文字等幾何圖形繪製操作PythonOpenCV