FJOI2015 最小覆蓋雙圓問題

2022-07-24 12:00:15 字數 2940 閱讀 3992

給定平面上n個點(x_1,y_1),...,(x_n,y_n)(x1​,y1​),...,(xn​,yn​),找出2個半徑相同的圓r_1r1​和r_2r2​,覆蓋給定的n個點,且半徑最小。

設計乙個演算法,計算出所求最小覆蓋雙圓 r_1r1​和 r_2r2​的半徑。

輸入有多個測試例項。每個例項的第1行中給出正整數n,n<1000,表示平面上有n個點。

接下來的n行中每行給出2個實數(x, y),-100000≤x≤100000,-100000≤y≤100000。

最後一行有乙個0表示結束。

對於每組資料,輸出最小的符合題意的圓的半徑,保留兩位小數。

輸入 #1

0.00 0.00 

1.00 0.00

0.00 4.00

10 0.00 0.00

0.00 3.00

1.00 6.00

2.00 2.00

3.00 5.00

5.00 3.00

6.00 3.00

9.00 5.00

10.00 5.00

11.00 3.00

0

輸出 #1

0.50

3.05
對於100%的資料,n<=1000n<=1000,|x_i|,|y_i|<=100000∣xi​∣,∣yi​∣<=100000,(t<=10t<=10)

【題目大意】

n個點,現在給兩個半徑相同的圓去覆蓋,求最小半徑

【解題思路】

我們需要盡量可能的減少重複的點,即同時被兩個圓覆蓋的點

所以我們二分列舉這個中間點,讓乙個圓覆蓋一部分

使點沒有重複的被覆蓋

一般情況下,我們直接按 x 排序二分

選擇半徑更大的一邊,然後繼續二分

但是這不行

因為這樣實際上是用一根垂直於 x 軸的直線分兩邊的點

而這個直線可能會有一定斜率

所以這個中間點的查詢就是乙個問題

二分列舉中間的分界點,因為通過圖可知

兩個圓總會關於一條直線對稱

兩圓不相交時是一條,兩圓相交時是他們的交線

我們需要一條直線將所有點分成兩半

但是正像上面所說,是被交線分開的

所以兩邊的點並不會一定被這根線分成兩半

於是我們列舉這根直線的斜率,同時為了更好的排序

我們直接旋轉座標系

旋轉座標系的過程參見線性代數

旋轉這一步我覺得是這道題的關鍵,而其他題解都沒有太說明

注意:對於變數的使用,要注意之前他是否被變更過

除錯**的時候可以通過調整檢視順序達到更高的效率

(先看main ---> 順序往下看)

#include#include

#include

#include

using

namespace

std;

const

int maxn = 2*1e3 + 5

;const

double inf =1e18 ;

const

double an = 1.0 / 180 * acos(-1

);const

double eps = 1e-9

;const

double si = sin(an), co =cos(an);

intn;

double reps()

struct

v v(

double a, double

b) :x(a), y(b) {}

v

operator+(const v&b) const

v

operator-(const v&b) const

bool

operator

double

operator*(const v&b) const

double

operator^(const v&b) const

//叉乘

v operator*(double b) const

v

operator/(double b) const

void rota()

v rot()

double len()

}p[maxn],o;

typedef v p;

struct

l friend p cross(l a, l b)

//求交點

};p circle(p a,p b, p c)

//求圓心

p s[maxn];

int sgn(double x)

double solve(int l,int

r) }

}return

r1;}

intmain()

double ans =inf;

///double cnt = 180;

for (int _ = 1; _ <= 181; _++)

for (int i = 1; i <= n; i++)

p[i].rota();

}printf(

"%.2lf\n

", sqrt(ans));

}return0;

}

view code

紀念我寫完的第一道黑題

FJOI2015 金幣換位問題

桌子上有2n 2個位置,其中前n個位置放著n個正面朝上的硬幣,接下來n個位置放著反面朝上的硬幣,後面兩個位置為空。每次操作可以將任意兩個相鄰的硬幣順序不變地移動到空位上,那麼至少要多少次操作可以將硬幣移成正反相間 正面的硬幣在第乙個,最後兩個還是空 例如 當n 4時,有一組合法解如下 1111000...

FJOI2015 火星商店問題

線段樹分治。以時間軸建立線段樹,每乙個線段樹節點,存放 l,r 時間內,有影響的操作1,建立可持久化trie樹,trie樹以商店位置為root,就可以支援商店的區間查詢,然後將操作0,按照商店位置排序,進行線段樹分治,每次到乙個節點,先把操作0插入trie樹,然後把所有當前時間記憶體的有影響的操作1...

題解 FJOI2015火星商店問題

好幾天之前做的題目了,一直想寫一下部落格也沒騰出時間來,今天趕緊把坑給填上呼呼呼 這道題首先如果只考慮每個商店中沒有時間限制的物品時,我們只需要使用一棵可持久化trie樹來維護區間內的異或最大值即可,這樣我們可以把兩部分的問題分離開來。之後我們再考慮有時間限制與編號限制的情況下,該怎樣做?無腦做法線...