小红的圆构造

[题目链接](https://www.nowcoder.com/practice/3309f6e285f04c74a8ee4804210224ca)

思路

给定一个坐标为 的点(),要构造一个同时与两条坐标轴相切且经过该点的圆,输出两个解的半径(升序)。

圆的性质

与两条坐标轴都相切的圆,其圆心到 轴和 轴的距离都等于半径 。因此圆心坐标为

由于点 在第一象限(),只有圆心在 的情况才能使圆经过该点(其他象限的圆心会导致距离过大或无解)。

列方程

圆心 ,半径 ,经过点

$$

(x - r)^2 + (y - r)^2 = r^2

$$

展开:

$$

x^2 - 2xr + r^2 + y^2 - 2yr + r^2 = r^2

$$

化简得到关于 的一元二次方程:

$$

r^2 - 2(x + y)r + (x^2 + y^2) = 0

$$

求解

由求根公式:

$$

r = \frac{2(x+y) \pm \sqrt{4(x+y)^2 - 4(x^2+y^2)}}{2} = (x+y) \pm \sqrt{2xy}

$$

判别式 (因为 ),所以恰好有两个正实数解。

较小的半径为 ,较大的为 ,直接输出即可。

样例验证

输入 ,即 ,与样例一致。

代码

#include <bits/stdc++.h>
using namespace std;
int main(){
    double x, y;
    scanf("%lf%lf", &x, &y);
    double s = x + y;
    double d = sqrt(2.0 * x * y);
    printf("%.8f %.8f\n", s - d, s + d);
    return 0;
}
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        double x = sc.nextDouble(), y = sc.nextDouble();
        double s = x + y;
        double d = Math.sqrt(2.0 * x * y);
        System.out.printf("%.8f %.8f%n", s - d, s + d);
    }
}
import math
x, y = map(int, input().split())
s = x + y
d = math.sqrt(2 * x * y)
print(f"{s - d:.8f} {s + d:.8f}")
const readline = require('readline');
const rl = readline.createInterface({ input: process.stdin });
rl.on('line', (line) => {
    const [x, y] = line.trim().split(/\s+/).map(Number);
    const s = x + y;
    const d = Math.sqrt(2 * x * y);
    console.log((s - d).toFixed(8) + ' ' + (s + d).toFixed(8));
    rl.close();
});

复杂度分析

  • 时间复杂度:,只需一次加法和一次开方运算。
  • 空间复杂度:,只使用常数个变量。