日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【FJOI2015】最小覆盖双圆问题

發布時間:2025/7/14 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【FJOI2015】最小覆盖双圆问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目描述

給定平面上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 3? 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|<=100000xi?,yi?<=100000,(T<=10T<=10)

?

【題目大意】

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

【解題思路】

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

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

使點沒有重復的被覆蓋

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

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

但是這不行

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

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

?

所以這個中間點的查找就是一個問題

?

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

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

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

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

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

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

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

我們直接旋轉坐標系

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

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

?

注意:

對于變量的使用,要注意之前他是否被變更過

調試代碼的時候可以通過調整查看順序達到更高的效率

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

?

#include<cstdio> #include<cmath> #include<algorithm> #include<iostream> 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); int n; double reps() { return (1.0*rand() / RAND_MAX - 0.5)*eps; } struct V {double x, y;V() {}V(double a, double b) :x(a), y(b) {}V operator+(const V&b) const { return V(x + b.x , y + b.y);}V operator-(const V&b) const { return V(x - b.x , y - b.y);}bool operator<(const V&b) const { return x < b.x; }double operator*(const V&b) const { return x * b.y - y * b.x; }double operator^(const V&b) const { return x * b.x + y * b.y; }//叉乘V operator*(double b) const { return V(x * b , y*b); }V operator/(double b) const { return V(x / b , y /b); }void rota() { double x1 = x, y1 = y;x=x1 * co - y1 * si, y=x1 * si + y1 * co; }V rot() { return V(-y, x); }double len() { return (x*x + y * y); }}p[MAXN],o; typedef V P; struct L {V s, t;L(P a,P b):s(a),t(b){}friend P cross(L a, L b) { return a.s + a.t*(b.t*(b.s - a.s)) / (b.t*a.t); }//求交點 }; P circle(P a,P b, P c) {return cross(L((a + b)*0.5, (b - a).rot()), L((a + c)*0.5, (c - a).rot())); } //求圓心 P s[MAXN]; int sgn(double x) { return x<-eps ? -1 : x>eps; } double solve(int l,int r) {double r1;if (l > r) return 0;int cnt = 0;for (int i = l; i <= r; i++)s[++cnt] = p[i];random_shuffle(s + 1, s + 1 + cnt);r1 = 0, o = s[1];for (int i = 1; i <= cnt; i++){if (sgn((s[i] - o).len() - r1)>0){o = s[i], r1 = 0;for (int j = 1; j <= i - 1; j++)if (sgn((s[j] - o).len()-r1) > 0){o = (s[i] + s[j])*0.5, r1 = (s[j] - o).len();for (int k = 1; k <= j - 1; k++)if (sgn((s[k] - o).len() - r1)>0)o = circle(s[i], s[j], s[k]), r1 = (s[i] - o).len();}}}return r1; } int main() {srand(20030719);while (scanf("%d", &n) && n){for (int i = 1; i <= n; i++){scanf("%lf%lf", &p[i].x, &p[i].y);}double ans = INF;///double cnt = 180;for (int _ = 1; _ <= 181; _++){sort(p + 1, p + 1 + n);int l = 1, r = n;//printf("**\n");while (l <= r){int mid = (l + r) >> 1;double retl = solve(1, mid); double retr = solve(mid + 1, n);//printf("**\n");double tmp = max(retl, retr);//if (retr + retl - tmp > ans) break;ans = min(tmp, ans);if (retl > retr) r = mid - 1;else l = mid + 1;}for (int i = 1; i <= n; i++)p[i].rota();}printf("%.2lf\n", sqrt(ans));}return 0; } View Code

?

?


紀念我寫完的第一道黑題

?

轉載于:https://www.cnblogs.com/rentu/p/11347191.html

總結

以上是生活随笔為你收集整理的【FJOI2015】最小覆盖双圆问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。