2016京东笔试编程题

这篇博客讲述了在2016年京东笔试中的一道编程题,涉及计算几何知识。题目要求找到一个点,从该点可以等角观察到三个圆形体育场,且当满足条件的点不唯一时,选取观察角度最大的点。博客内容介绍了如何解决这个问题,并强调了在实际比赛场景中,所有比赛场地的观察重要性均等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2016京东笔试编程题
题意如下:

The Olympic Games in Bercouver are in full swing now. Here everyone has their own objectives: sportsmen compete for medals, and sport commentators compete for more convenient positions to give a running commentary. Today the main sport events take place at three round stadiums, and the commentator's objective is to choose the best point of observation, that is to say the point from where all the three stadiums can be observed. As all the sport competitions are of the same importance, the stadiums should be observed at the same angle. If the number of points meeting the conditions is more than one, the point with the maximum angle of observation is prefered.

Would you, please, help the famous Berland commentator G. Berniev to find the best point of observation. It should be noted, that the stadiums do not hide each other, the commentator can easily see one stadium through the other.

Input

The input data consists of three lines, each of them describes the position of one stadium. The lines have the format x,  y,  r, where (x, y) are the coordinates of the stadium's center ( -  103 ≤ x,  y ≤ 103), and r (1 ≤ r  ≤ 103) is its radius. All the numbers in the input data are integer, stadiums do not have common points, and their centers are not on the same line.

Output

Print the coordinates of the required point with five digits after the decimal point. If there is no answer meeting the conditions, the program shouldn't print anything. The output data should be left blank.

解题思路:
其实很容易列出两个二元二次方程。可以直接通过求解该方程。只是比较复杂而已。可以参见如下程序:
//
//  main.cpp
//  hiho_110
//
//  Created by chenalong on 8/10/16.
//  Copyright (c) 2016 chenalong-Arc_Point_2014_hunan. All rights reserved.
//

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
#include <map>
#include <cmath>
#include <set>
#include <queue>

using namespace std;

#define eps 1e-6

struct node
{
    double val,x_val,x_2_val;
};

// 分别表示 常数项,一次项,二次项系数
void init_node(node& tmp)
{
    tmp.val = 0;
    tmp.x_2_val = 0;
    tmp.x_val = 0;
}

// 把 lamba(x - constant) ^ 2 相关系数加入到统计量中去
void add_val(node& tmp,int lamba,int constant)
{
    tmp.val += 1.0 * lamba * constant * constant;
    tmp.x_val += 1.0 * -lamba * 2 * constant;
    tmp.x_2_val += lamba;
}

// 每个系数都乘以一个常数
void multi_val(node& tmp, int constant)
{
    tmp.val *= constant;
    tmp.x_2_val *= constant;
    tmp.x_val *= constant;
}

// 两个方程相减,就是相对应的系数相减
void sub_val(node& tmp1,node& tmp2)
{
    tmp1.val -= tmp2.val;
    tmp1.x_val -= tmp2.x_val;
    tmp1.x_2_val -= tmp2.x_2_val;
}

// 程序的输入,表示圆心坐标和半径大小
int x[4],y[4],r[4];

//解二元一次方程
bool solve_quadratic(double a,double b,double c,double& answer1,double& answer2)
{
    if(fabs(a) < eps)
    {
        answer2 = answer1 = -c / b;
        return true;
    }
    else
    {
        double sq = b * b - 4 * a * c;
        if(sq < -eps)
            return false;
        answer1 = (-b + sqrt(sq)) / 2 / a;
        answer2 = (-b - sqrt(sq)) / 2 / a;
        return true;
    }
}

// 计算一个数的平方
double square(double a)
{
    return a * a;
}

// 判断得到的解是否正确
void verify(double x1,double y1)
{
    for(int i= 1;i<=3;i++)
    {
        cout << sqrt(square(x1 - x[i]) + square(y1 - y[i])) << endl;
    }
}


// 判断输出那个点
void output(double x1,double y1,double x2,double y2)
{
    if(square(x1 - x[1]) + square(y1 - y[1]) < square(x2-x[1]) + square(y2-x[1]))
    {
        printf("%.5lf %.5lf\n",x1,y1);
        //verify(x1,y1);
    }
    else
    {
        printf("%.5lf %.5lf\n",x2,y2);
        //verify(x2, y2);
    }
}

// 寻找满足条件的点
void solve(node& a1,node& b1,node& a2, node& b2)
{
    // 两个解
    double x1,y1,x2,y2;
    //二次方程的系数
    double a,b,c;
    //标志是否有解
    bool flag = true;
    
    if(fabs(a2.x_val) <eps)
    {
        y1 = y2 = (a2.val + b2.val) * 1.0/ (-b2.x_val);
        
        a = a1.x_2_val;
        b = a1.x_val;
        c = 0.0 + a1.val + b1.x_2_val * y1 * y1 + b1.x_val * y1 + b1.val;
        
        flag = solve_quadratic(a, b, c, x1, x2);
    }
    else if(fabs(b2.x_val) <eps)
    {
        x1 = x2 = (a2.val + b2.val) * 1.0/ (-a2.x_val);
        
        a = b1.x_2_val;
        b = b1.x_val;
        c = 0.0 + b1.val + a1.x_2_val * x1 * x1 + a1.x_val * x1 + a1.val;
        
        flag = solve_quadratic(a, b, c, y1, y2);
    }
    else
    {
        double constant = a2.val + b2.val;
        double coff1 = -constant / b2.x_val;
        double coff2 = -a2.x_val / b2.x_val;
        
        a = 0.0 + a1.x_2_val + b1.x_2_val * coff2 * coff2;
        b = 0.0 + a1.x_val + b1.x_2_val * (2 * coff1 * coff2) + b1.x_val * coff2;
        c = 0.0 + a1.val + b1.val + b1.x_2_val *(coff1 * coff1) + b1.x_val * coff1;
        
        flag = solve_quadratic(a, b, c, x1, x2);
        
        y1 = coff1 + coff2 * x1;
        y2 = coff1 + coff2 * x2;
    }
    
    if(flag)
    {
        output(x1,y1,x2,y2);
    }
}

int main()
{
    
    for(int i = 1;i<=3;i++)
        cin >> x[i] >> y[i] >> r[i];
    
    for(int i = 1;i<4;i++)
        r[i] *= r[i];

    node a1,b1,a2,b2;
    init_node(a1);
    init_node(a2);
    init_node(b1);
    init_node(b2);
    
    // 根据距离关系构建两个二元二次方程
    add_val(a1,r[2],x[1]);
    add_val(a1,-r[1],x[2]);
    
    add_val(b1,r[2],y[1]);
    add_val(b1,-r[1],y[2]);
    
    add_val(a2,r[3],x[1]);
    add_val(a2,-r[1],x[3]);
    
    add_val(b2,r[3],y[1]);
    add_val(b2,-r[1],y[3]);
    
    //根据不同条件消除二次项,把 y 用 x 来表示
    if(r[3] == r[1])
    {
        solve(a1,b1,a2,b2);
    }
    else if(r[2] == r[1])
    {
        solve(a2,b2,a1,b1);
    }
    else
    {
        // 两个方程相减消除平方项
        multi_val(a1, r[3] - r[1]);
        multi_val(b1, r[3] - r[1]);
        
        multi_val(a2, r[2] - r[1]);
        multi_val(b2, r[2] - r[1]);
        
        sub_val(a1,a2);
        sub_val(b1,b2);
        
        solve(a2,b2,a1,b1);
    }
    
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值