链接:https://www.nowcoder.com/acm/contest/151/D
来源:牛客网
题目描述
有一个神奇的盘子,形状为圆形。盘子上面爬着一个大象(视作一个点)。由于现实的扭曲,当大象在盘子某个直径的一端的时候,可以瞬间传送至直径的另一端。现在大象想去盘子上另外一点,问他最少需要移动多少距离。传送不计距离。
输入描述:
第一行一个整数r(1 <= r <= 1000)代表盘子的半径。 接下来两行两个整点分别代表大象所在的位置和大象目标的位置坐标。保证两个点都在圆内(可能在边界上),圆心在点(0, 0)上。
输出描述:
输出一个实数,代表大象最短需要移动多少距离。和标程相对或绝对相差1e-6都算正确。
随机暴力能过就好
直接对极坐标模拟退火找到最优的点,精确度还是很高的
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define PI acos(-1.0)
double x, y, x1, yl, x2, y2, R;
double Dis(double a, double b, double c, double d)
{
return sqrt((a-c)*(a-c)+(b-d)*(b-d));
}
void Jud(double k)
{
while(k>=PI)
k -= PI;
if(k>=PI/2 || k<=-PI/2)
y = R*sin(k), x = -sqrt(R*R-y*y);
else
y = R*sin(k), x = sqrt(R*R-y*y);
}
double Rand()
{
return rand()%1000/1000.0;
}
double Do(double p)
{
Jud(p);
return Dis(x, y, x1, yl)+Dis(-x, -y, x2, y2);
}
double SA(double T)
{
double dx, now, temp;
now = 0; Do(now);
while(T>0.0001)
{
temp = now+T*(Rand()*2-1);
dx = Do(now)-Do(temp);
if(dx>0)
now = temp;
T = T*0.9993;
}
return Do(now);
}
int main(void)
{
scanf("%lf%lf%lf%lf%lf", &R, &x1, &yl, &x2, &y2);
printf("%.10f\n", min(Dis(x1, yl, x2, y2), SA(PI/2)));
return 0;
}