我們設一個圓的圓心坐標為 ,半徑為 r 。那么這個圓的方程可以寫為:
在這個圓上隨便取三個點,設這三個點的坐標分別是 那么有:
公式(1)(2)相減,(1)(3)相減之后經過化簡可以得到:
有唯一解的條件是系數行列式不為 0 :
簡單變變型也就是:
這樣寫幾何含義就很明顯了,三點不能共線。
設:
那么 :
有了 x 0 和 y 0 的值后,帶入(1) 式就可以得到 r 的值。至此,三點確定圓的問題就解決了。
三點共圓求圓心的模版:
double X, Y; struct Point { double x, y; } a[2005]; void solve(Point a, Point b, Point c) //三點共圓圓心公式 { double fm1=2 * (a.y - c.y) * (a.x - b.x) - 2 * (a.y - b.y) * (a.x - c.x); // 2 (da - bc) double fm2=2 * (a.y - b.y) * (a.x - c.x) - 2 * (a.y - c.y) * (a.x - b.x); // 2 (bc - ad) if (fm1 == 0 || fm2 == 0) { X = Y = 1e18; return; } double fz1=a.x * a.x - b.x * b.x + a.y * a.y - b.y * b.y; // e double fz2=a.x * a.x - c.x * c.x + a.y * a.y - c.y * c.y; // f X = (fz1 * (a.y - c.y) - fz2 * (a.y - b.y)) / fm1; // x0 Y = (fz1 * (a.x - c.x) - fz2 * (a.x - b.x)) / fm2; // y0 }
例題:Boundary
題意:
給了n個點,讓你自己隨便定義圓心(圓心不要求是n個點的其中一個)和半徑,要求這n個點有盡可能多的點在圓上,並且該圓經過坐標原點(0,0)。求滿足的圓上的點最多有多少個。
想法:
由於必須經過原點,所以我們可以只枚舉兩個點從而就可以達到枚舉圓心的目的。【因為三點共圓】
用vector保存下來這些圓心坐標。
處理完后,對圓心坐標sort一下,判斷有多少個圓心坐標是一樣的。
再要尋找有幾個點在圓上,我們可以枚舉圓上的點。
滿足 x * (x - 1 ) / 2 == ans
這個時候的 x 就是我們所求的
#include <algorithm> #include <string> #include <cstring> #include <vector> #include <map> #include <stack> #include <set> #include <queue> #include <cmath> #include <cstdio> #include <iomanip> #include <ctime> #include <bitset> #include <cmath> #include <sstream> #include <iostream> #include <unordered_map> #define ll long long #define ull unsigned long long #define ls nod<<1 #define rs (nod<<1)+1 #define pii pair<int,int> #define mp make_pair #define pb push_back #define INF 0x3f3f3f3f #define max(a, b) (a>b?a:b) #define min(a, b) (a<b?a:b) const double eps = 1e-8; const int maxn = 2e5 + 10; const ll MOD = 99999999999999; const int mlog=20; int sgn(double a) { return a < -eps ? -1 : a < eps ? 0 : 1; } using namespace std; double X, Y; struct Point { double x, y; } a[2005]; void solve(Point a, Point b, Point c) //三點共圓圓心公式 { double fm1=2 * (a.y - c.y) * (a.x - b.x) - 2 * (a.y - b.y) * (a.x - c.x); // 2 (da - bc) double fm2=2 * (a.y - b.y) * (a.x - c.x) - 2 * (a.y - c.y) * (a.x - b.x); // 2 (bc - ad) if (fm1 == 0 || fm2 == 0) { X = Y = 1e18; return; } double fz1=a.x * a.x - b.x * b.x + a.y * a.y - b.y * b.y; // e double fz2=a.x * a.x - c.x * c.x + a.y * a.y - c.y * c.y; // f X = (fz1 * (a.y - c.y) - fz2 * (a.y - b.y)) / fm1; // x0 Y = (fz1 * (a.x - c.x) - fz2 * (a.x - b.x)) / fm2; // y0 } vector<pair<double,double>> mpp; int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%lf%lf", &a[i].x, &a[i].y); for (int i = 1; i <= n; i++){ for (int j = i + 1; j <= n; j++){ solve({0, 0}, a[i], a[j]); if (X == Y && sgn(X-1e18) == 0) continue; mpp.push_back({X,Y}); } } if(mpp.size()==0){ putchar('1'); return 0; } sort(mpp.begin(),mpp.end()); int ma = 1; int num = 1; pair<double,double> now=mpp[0]; for(int i=1;i<mpp.size();i++){ if(mpp[i]==now) ++num; else{ now=mpp[i]; ma=max(ma,num); num=1; } ma=max(ma,num); } for (int i = 1; i <= n; i++){ if (i * (i - 1) == ma * 2){ printf("%d\n", i); return 0; } } return 0; }