三点共圆公式
我們設一個圓的圓心坐標為,半徑為 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
", i);
return 0;
}
}
return 0;
}
總結
- 上一篇: Arduino串口不够用怎么办?
- 下一篇: 如何用Excel画出美观的图或表Exce