题目
在数码世界的某次战争中,年轻的狮子兽收到了一封密函,密函中指出需要让他从当前坐标赶往另一个坐标去狙击敌人的精英部队。但是狮子兽知道,整个战场都有可能被敌方的飞行兽从上往下侦查到,因此需要注意隐匿自己的行踪。
狮子兽虽然年轻,但他对战场非常了解,他知道在战场上存在N个无法被飞行兽侦查到的浮空圆盘,只要在浮空圆盘内部(包括圆盘边界,下同)就不会被飞行兽侦查到(浮空圆盘可能重叠)。
现在狮子兽想要从当前坐标前往指定坐标(假设其行进速度恒定,1单位时间行进1单位距离),但是为了减少暴露自己的可能,所以想使不在浮空圆盘内部的时间尽可能少。
注意:整个战场是一个连续二维坐标平面,地势平缓,且狮子兽的行进可以是任何方向、可以是直线也可以是曲线。
Input
每个输入文件中一组数据。
第一行一个正整数N(1<=N<=1000),表示浮空圆盘的个数。
接下来N行,每行三个整数x, y, r(-1000<=x,y<=1000、0<=r<=10),分别代表浮空圆盘的坐标(x,y)和半径r。
最后分两行给出狮子兽的当前坐标和目的坐标,每行两个整数x, y(-1000<=x,y<=1000)。
输出格式
输出不在浮空圆盘内部的最少时间(即不得不暴露在飞行兽侦查下的最少时间)。结果精度保留两位小数。
Output
输出不在浮空圆盘内部的最少时间(即不得不暴露在飞行兽侦查下的最少时间)。结果精度保留两位小数。
Simple Input
1
0 0 1
2 0
0 2
Simple Output
2.00
思路:这就是一道披着狮子兽的最短路。把时间转换成两圆盘之间路径的权值,两圆盘路径的权值=两圆盘的圆心距离-两圆盘各自的半径,圆盘重叠权值就为0。起点和终点就相当于半径为0的圆盘。然后就是最短路了。
下面是代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
double matrix[1005][1005];
int n;
int x[1005],y[1005],r[1005];
int k,mark[1005];
double minn,dist[1005];
void Dijkstra(int x)
{
for(int i=1;i<=n;i++) {
mark[i] = 0;
dist[i] = matrix[x][i];
}
mark[x] = 1;
do {
minn=MOD;
k=0;
for(int i=1;i<=n;i++)
if(mark[i]==0 && dist[i]<minn) {
minn = dist[i];
k = i;
}
if(k) {
mark[k] = 1;
for(int i=1;i<=n;i++)
if(matrix[k][i]<MOD && minn+matrix[k][i]<dist[i]) {
dist[i] = minn + matrix[k][i];
}
}
}while(k);
printf("%.2lf\n",dist[n]);
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&x[i],&y[i],&r[i]);
}
scanf("%d%d%d%d",&x[n+1],&y[n+1],&x[n+2],&y[n+2]);
r[n+1]=r[n+2]=0;
n+=2;
for(int i=1;i<=n;i++)
{
matrix[i][i]=MOD;
for(int j=1;j<i;j++)
{
//cout<<x[i]<<" "<<y[i]<<' '<<x[j]<<' '<<y[j]<<endl;
//计算路径权值
matrix[i][j]=matrix[j][i]=max(0.0,sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]))-r[i]-r[j]);
//printf("%lf\n",matrix[i][j]);
}
}
Dijkstra(n-1);
}
}