2020牛客暑期多校訓練營(第二場)B - Boundary - 計算幾何
阿新 • • 發佈:2020-07-20
Description
給定二維平面上的 \(n\) 個點,求一個過原點的圓,使得圓周經過的給定點的數目最大。\(n \le 2000\)
Solution
標答的做法:
同弧所對的圓周角相等
列舉所有點 \(P\),設 \(OP\) 為一條弦,此時若列舉另一點 \(A\),則可確定一圓
當確定 \(OP\) 後,圓的唯一自由量可以視作半徑,而 \(OP\) 在同樣半徑的圓上對應的圓周角相等
因此我們可以對剩下所有點 \(A\) 計算出圓周角 \(\angle OAP\),取眾數即可
考慮到一個角度會有對稱的兩個 \(A\) 與其對應,因此我們強行約束 \(OA \times OP >0\)
其實這樣誤差可能比較大,標程用了分數類之類的操作,比較麻煩
我們考慮直接用三點共圓座標公式解決問題,總體思路和上面的方法相同,不過是把角度換成圓心座標罷了
#include <bits/stdc++.h> using namespace std; #define int long long const int N = 2005; struct point { double x,y; double operator * (const point &b) { return x*b.y-y*b.x; } double len2() { return x*x+y*y; } bool operator < (const point &b) const { return x==b.x?y<b.y:x<b.x; } } p[N]; int n,ans; signed main() { ios::sync_with_stdio(false); cin>>n; for(int i=1;i<=n;i++) cin>>p[i].x>>p[i].y; for(int i=1;i<=n;i++) { map<point,int> mp; for(int j=i+1;j<=n;j++) { double d=p[i]*p[j],d1=p[i].len2(),d2=p[j].len2(); if(fabs(d)<1e-6) continue; double x=(p[i].y*d2-p[j].y*d1)/d, y=(p[i].x*d2-p[j].x*d1)/d; ans=max(ans,++mp[{x,y}]); } } cout<<ans+1<<endl; }