三點共圓公式


我們設一個圓的圓心坐標為 image.png,半徑為 r 。那么這個圓的方程可以寫為:
image.png

在這個圓上隨便取三個點,設這三個點的坐標分別是 image.png那么有:

image.png

公式(1)(2)相減,(1)(3)相減之后經過化簡可以得到:
image.png

image.png有唯一解的條件是系數行列式不為 0 :
image.png

 

簡單變變型也就是:
image.png

這樣寫幾何含義就很明顯了,三點不能共線。

設:
image.png

那么 :
image.png

有了 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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2024 CODEPRJ.COM