2020牛客暑期多校训练营(第二场)B Boundary

2020/7/14
这里使用两种做法:

  • 已知答案的圆过原点,因此最终在圆上的点与原点的垂直平分线必过圆心,计算出n个点与原点的垂直平分线,这n条直线两两之间有n*(n-1)/2个交点。找到这n*(n-1)/2个点中某个点出现最多的次数其次数就是答案(因为垂直平分线的交点相同表示圆心重合,且圆过原点所以他们所在的圆为同一个圆)。
    推交点的过程并不复杂,最后联立方程组2次分别解出交点的坐标(xi,yi),(不要把x带入到垂直平分线求y,更麻烦)即可
    代码:
#include
#define rep(i,a,b) for(int i=a;i
using namespace std;
const int maxn=2e3+9;
typedef pair<double,double> pdd;
int n;
double x[maxn],y[maxn];
map<pdd,int> res;
int main(){
    scanf("%d",&n);
    rep(i,0,n) scanf("%lf%lf",x+i,y+i);
    int ans=0;
    rep(i,0,n) {
        res.clear();
        rep(j,i+1,n){
            if(x[i]*y[j]==x[j]*y[i]) continue;
            double d=x[i]*y[j]-x[j]*y[i],d1=x[i]*x[i]+y[i]*y[i],d2=x[j]*x[j]+y[j]*y[j];
            double X=(y[i]*d2-y[j]*d1)/d,Y=(x[i]*d2-x[j]*d1)/d;
            ans=max(ans,++res[{X,Y}]);
        }
    }
    printf("%d\n",ans+1);
}
  • 第二种做法就是题解给出的:
    2020牛客暑期多校训练营(第二场)B Boundary_第1张图片
    代码:
#include 
#include 
#include 
using namespace std;
typedef long long LL;
const double eps = 1e-15;
const int N = 2010;
int X[N], Y[N];
double A[N];
int Cross(int lhs, int rhs) { // 向量叉积
    return X[lhs] * Y[rhs] - X[rhs] * Y[lhs];
}
int Dis2(int lhs, int rhs) { // 两点欧氏距离的平方
    int dx = X[lhs] - X[rhs], dy = Y[lhs] - Y[rhs];
    return dx * dx + dy * dy;
}
double GetCosAngle2(int i, int j) { // Oi对角的cos值
    int a2 = Dis2(0, i), b2 = Dis2(i, j), c2 = Dis2(0, j);
    return (double)(b2 + c2 - a2) / 2 / sqrt(b2) / sqrt(c2);
}
 
int main()
{
    int n, ans = 1;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d%d", X + i, Y + i);
    for (int i = 1; i <= n; i++) {
        int cnt = 0;
        for (int j = 1; j <= n; j++) if (Cross(i, j) < 0) A[++cnt] = GetCosAngle2(i, j);
        sort(A + 1, A + cnt + 1);
        for (int l = 1, r; l <= cnt; l = r) {
            for (r = l; fabs(A[l] - A[r]) < eps && r <= cnt; r++);
            ans = max(ans, r - l + 1);
        }
    }
    printf("%d\n", ans);
    return 0;
}

你可能感兴趣的:(刷题记录,算法,几何学)