开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情
AcWing 4499. 画圆
在一个二维平面内,给定一个以 (x1,y1) 为圆心,半径为 R 的圆以及一个坐标为 (x2,y2) 的点。
请你在二维平面上画一个圆,要求:
- 平面中不存在点满足既在你画的圆上,又在给定的圆外。
- 给定的点不能在你画的圆内(可以在圆上)。
- 被给定圆覆盖且不被你画的圆覆盖的区域面积应尽可能小。
请输出你画的圆的圆心坐标以及半径。
输入格式
共一行,包含 5 个整数 R,x1,y1,x2,y2。
输出格式
三个实数 xans,yans,r,其中 (xans,yans) 是你画的圆的圆心坐标,r 是你画的圆的半径。
答案不唯一时,输出任意合理答案均可。
结果保留六位小数。
数据范围
所有测试点满足 1≤R≤105,|x1|,|y1|,|x2|,|y2|≤105。
输入样例1:
5 3 3 1 1
输出样例1:
3.767767 3.767767 3.914214
输入样例2:
10 5 5 5 15
输出样例2:
5.000000 5.000000 10.000000
思路
这个题其实偏几何,虽然说是acw周赛的第三题,但是其实想明白了就很简单。分析题目就可以知道如果那个点在圆外,是肯定无法满足题意的,所以这个点只能在圆内或者刚好在圆上。不管这个点在圆内还是圆上,都需要用到两点之间的距离公式,这个当然很简单啦,最后比较一下两个情况哪个更短,按题目要求输出就好啦。总的来说,就是分情况加上一点点几何知识就欧克啦。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
double cal(int x,int y,int xx,int yy){
int ds=abs(x-xx);
int dy=abs(y-yy);
if(!ds&&!dy)return 0.0;
return (double)sqrt((double)(ds*ds+dy*dy));
}
signed main(){
int r,x,y,xx,yy;
cin>>r>>x>>y>>xx>>yy;
// cout<<r<<" "<<x<<" "<<y<<" "<<xx<<" "<<yy<<endl;
if(cal(x,y,xx,yy)>=(double)r){
printf("%.6lf %.6lf %.6lf\n",(double)(x),(double)(y),(double)(r));
return 0;
}
if(x==xx&&y==yy){
double ansr=r;
double dx1=x+r;
double dy1=y;
printf("%.6lf %.6lf %.6lf\n",(double)((double)xx+dx1)/2,(double)((double)yy+dy1)/2,(double)ansr/2);
}
else{
double ansr=cal(x,y,xx,yy)+r;
double k=(double)(ansr/cal(x,y,xx,yy));
double dy=k*(abs(y-yy));
double dx=k*(abs(x-xx));
double dx1=0,dy1=0;
if(xx>=x&&yy>=y){
dx1=(xx-dx);
dy1=yy-dy;
}
else if(xx<=x&&yy>=y){
dx1=(xx+dx);
dy1=yy-dy;
}
else if(xx>=x&&yy<=y){
dx1=(xx-dx);
dy1=yy+dy;
}
else if(xx<=x&&yy<=y){
dx1=(xx+dx);
dy1=yy+dy;
}
printf("%.6lf %.6lf %.6lf\n",(double)(xx+dx1)/2,(double)(yy+dy1)/2,(double)ansr/2);
}
return 0;
}