24h購物| | PChome| 登入
2013-03-29 08:21:49| 人氣1,300| 回應1 | 上一篇 | 下一篇

[ZJ][圓并、圓交、周長] a648. A - Red Areas

推薦 0 收藏 0 轉貼0 訂閱站台

內容 :

根據可靠消息指出,恐怖份子在Taike city中四週設置了許多炸彈。並計畫在過年前夕引爆。爆炸將會對城市造成無數的破壞,所以政府必須盡快做出所有能做的防範措施來降低潛在危險。

幸 運的是,經過ASF小組(Army Special Forces)的調查,我們能夠清楚的知道炸彈的位置和影響範圍,我們將此範圍稱之為Red Area。Red Area是一個以炸彈為中心的圓形區域,給定有N個炸彈,第i個炸彈的位置在(xi,yi),它的Red Area半徑為ri。

Tauke city決定在所有Red Area的邊界上圍上封鎖線,現在你的工作就是去計算這些封鎖線的總長度。Red Area有可能互相重疊,形成不是圓形的範圍。也可能有數個獨立的安全區域,被Red Area包圍住,但是卻不會被炸彈波及到。

舉 例來說,如圖1,城市中有兩顆炸彈,位置分別是 (0,0) 和 (2,0) ,它們的Red Area半徑都是2。因為兩炸彈的Red Area有互相重疊,所以可以被一條封鎖線包圍,封鎖線的總長度是16.76。再舉個例,如圖2,程式中有八顆炸彈,位置分別為 (1,1) , (1,3) , (1,5) , (3,1) , (3,5) , (5,1) , (5,3) 和 (5,5),它們的Red Area半徑為1,八顆炸彈的Red Area包圍出一個獨立的安全區域(用陰影部分表示),所以需要的封鎖線包括了內部和外部兩條,兩條線的長度合為50.27。

 

Hint:圓的周長 L = 2πr , π = 3.14159265 , r是圓的半徑。

技術規格

1.炸彈的數量N是一個整數,且 1 <= N <= 100。
2.第i個炸彈的座標和半徑都是整數,且 -900 <= xi <= 900 、 -900 <= yi <= 900 、 0 < ri <= 20

3.每個炸彈的位置都不同,任兩個炸彈不會有同樣的座標。 


輸入說明 :

input的第一行有一個正整數表示接下來有幾組測資。每組測資的第一行有一個正整數N,表示這組測資有幾顆炸彈。接下來的N行,每行都有三個由空格分開的整數,xi , yi , 和 ri , ,表示了第i個炸彈的座標和Red Area的半徑。

輸出說明 :

請印出兩個數字,由一個空格隔開。第一個數字a是一個實數, 0 < a < 10 。第二個數字是一個非負整數。而封鎖線的總長度為用科學符號表示的a×10b。注意,a需印出小數後兩位。

範例輸入 :

2
2 
0 0 2 
2 0 2 
8 
1 1 1 
1 3 1 
1 5 1 
3 1 1 
5 1 1 
5 3 1 
3 5 1 
5 5 1 

範例輸出 :

1.68 1
5.03 1 

提示 :

Like to bet?

 

出處 :

陳伶志, PTC 2008 TOI2013 練習題 (管理:stanley17112000)

思路:

對每個圓 A[i] 找到另一個圓 A[j] 與它交兩點,
然後得到這兩點在圓 A[i] 的 theta1, theta2 [-pi, pi] 之間,
然後取 (theta1+theta2)/2 判斷是否在 A[j] 圓中,
如果不在拆成兩個區間 [-pi, theta1] [theta2, pi],否則 [theta1, theta2]
對於一個圓 A[i] 找到 [-pi, pi] 之間沒有被覆蓋的許多區間,
最後加總答案,ans += A[i].r * sigma(↑.length());



考虑上图中的蓝色圆,绿色的圆和蓝色的圆交于 A,B 2个交点 ,我们在逆时针系下考虑,那么 可以知道 对于蓝色的圆,它对应的某个 角度区间被覆盖了

假设 区间为 [A, B], 并且角度是按照 圆心到交点的 向量的 极角来定义 (为了方便,我一般都把角度转化到 [-pi,pi]区间内) 那么可以知道在这种 标识情况下,可能存在以下情况

这种区间的跨度如何解决呢?实际上十分简单,只需要把[A,B] 拆成 [-pi, A], [B,pi]即可,也就是所谓的添加虚拟点。

說明取自 http://hi.baidu.com/aekdycoin/item/b8ff6adc73c0e71dd78ed0d6

整體 O(n*n*logn)


#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
struct Cir {
    double x, y, r;
    int scan() {
        return scanf("%lf %lf %lf", &x, &y, &r) == 3;
    }
};
#define eps 1e-8
struct Pt {
    double x, y;
    bool operator<(const Pt other) const {
        if(fabs(x-other.x) < eps)
            return y < other.y;
        return x < other.x;
    }
};
int IntersectCir(Cir A, Cir B, Pt v[]) { // Pt v[] result buffer
    double disAB = sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
    if(A.r+B.r+eps < disAB || A.r+disAB+eps < B.r || B.r+disAB+eps < A.r) {
        if(disAB < B.r-A.r)
            return 3; //cover all special case
        return -1;
    }
    double vx, vy;
    vx = B.x - A.x;
    vy = B.y - A.y;
    if(fabs(disAB-A.r-B.r) < eps || fabs(A.r-disAB-B.r) < eps ||
       fabs(B.r-A.r-disAB) < eps) {
        if(fabs(disAB-A.r-B.r) < eps) {//(A)(B)
        } else {
            if(A.r < B.r) { //((A)B)
                v[0].x = A.x-vx*A.r/(B.r-A.r);
                v[0].y = A.y-vy*A.r/(B.r-A.r);
                return 3; // cover all special case
            }//((B)A)
        }
        return 1;
    }
    double theta = acos((A.r*A.r+disAB*disAB-B.r*B.r)/2/A.r/disAB);
    double rvx, rvy;
    rvx = vx*cos(theta)-vy*sin(theta);
    rvy = vx*sin(theta)+vy*cos(theta);
    v[0].x = A.x+rvx*A.r/disAB;
    v[0].y = A.y+rvy*A.r/disAB;
    rvx = vx*cos(-theta)-vy*sin(-theta);
    rvy = vx*sin(-theta)+vy*cos(-theta);
    v[1].x = A.x+rvx*A.r/disAB;
    v[1].y = A.y+rvy*A.r/disAB;
    return 2;
}
const double pi = acos(-1);
int main() {
    int t, n;
    int i, j, k;
    scanf("%d", &t);
    Cir D[105];
    while(t--) {
        scanf("%d", &n);
        for(i = 0; i < n; i++)
            D[i].scan();
        double ans = 0, L, R, M, tx, ty;
        int Iidx;
        Pt Interval[205], p[2];
        for(i = 0; i < n; i++) {
            Iidx = 0;
            for(j = 0; j < n; j++) {
                if(i == j)  continue;
                int r = IntersectCir(D[i], D[j], p);
                if(r == 3)  break;
                if(r < 2)   continue;
                L = atan2(p[0].y-D[i].y, p[0].x-D[i].x);
                R = atan2(p[1].y-D[i].y, p[1].x-D[i].x);
                if(L > R)
                    M = L, L = R, R = M;
                M = (L+R)/2;
                tx = D[i].x+D[i].r*cos(M);
                ty = D[i].y+D[i].r*sin(M);
                if(pow(tx-D[j].x,2)+pow(ty-D[j].y, 2) < pow(D[j].r, 2)) {
                    Interval[Iidx].x = L;
                    Interval[Iidx++].y = R;
                } else {
                    Interval[Iidx].x = -pi;
                    Interval[Iidx++].y = L;
                    Interval[Iidx].x = R;
                    Interval[Iidx++].y = pi;
                }
            }
            if(j != n)  continue;
            sort(Interval, Interval+Iidx);
            double rr = -pi;
            for(j = 0; j < Iidx; j++) {
                if(Interval[j].x < rr+eps)
                    rr = max(Interval[j].y, rr);
                else {
                    ans += D[i].r*(Interval[j].x-rr);
                    rr = Interval[j].y;
                }
            }
            ans += D[i].r*(pi-rr);
        }
        double a = log10(ans), b;
        b = floor(a);
        a = a-b;
        printf("%.2lf %d\n", pow(10, a), (int)b);
    }
    return 0;
}

台長: Morris
人氣(1,300) | 回應(1)| 推薦 (0)| 收藏 (0)| 轉寄
全站分類: 不分類 | 個人分類: ZeroJudge |
此分類下一篇:[ZJ][蒙地卡羅模擬法] a648. A - Red Areas
此分類上一篇:[ZJ] a647. 投資專家

Morris
http://140.122.185.166/ZeroJudge/ShowProblem?problemid=d012
但目前過不了這一題的測資,求解法。
2013-03-29 08:45:44
版主回應
那題似乎只能用蒙地卡羅模擬法過
2013-04-15 20:44:10
是 (若未登入"個人新聞台帳號"則看不到回覆唷!)
* 請輸入識別碼:
請輸入圖片中算式的結果(可能為0) 
(有*為必填)
TOP
詳全文