题目大意:
题目链接:http://www.rqnoj.cn/problem/86
一个坐标系上有个点条边,有两种移动方式:
- 经过一条边从一个点到达另一个点,耗时为这条边长度
- 从一个点垂直跳下到达正下方的另一个点。耗时为 (注意:取)
求从点到点的最小时间。
思路:
对于移动方式,直接利用勾股求出两点之间的距离,然后建一条双向边。
对于移动方式,就枚举所有的点,判断他们是否满足且,如果满足,那么就在到中连一条单向边
。
然后跑个最短路就可以了。
代码:
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <queue>
#define N 200
using namespace std;
int n,tot,head[N];
double v,dis[N];
bool vis[N];
struct edge
{
int next,to;
double dis;
}e[N*2];
struct node
{
double x,y;
}a[N];
double ask_dis(double x1,double y1,double x2,double y2) //勾股求距离
{
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
void add1(int from,int to) //移动方式1
{
e[++tot].to=to;
e[tot].dis=ask_dis(a[from].x,a[from].y,a[to].x,a[to].y)/v/1.0;
e[tot].next=head[from];
head[from]=tot;
}
void add2(int from,int to,double dis) //移动方式2
{
e[++tot].to=to;
e[tot].dis=dis;
e[tot].next=head[from];
head[from]=tot;
}
void spfa()
{
for (int i=1;i<=n;i++)
{
dis[i]=1000000000.0;
vis[i]=0;
}
queue<int> q;
q.push(1);
dis[1]=0.0;
vis[1]=1;
while (q.size())
{
int u=q.front();
q.pop();
vis[u]=0;
for (int i=head[u];~i;i=e[i].next)
{
int v=e[i].to;
if (dis[v]>dis[u]+e[i].dis)
{
dis[v]=dis[u]+e[i].dis;
if (!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
}
int main()
{
memset(head,-1,sizeof(head));
cin>>n>>v;
int x,y,fa;
for (int i=1;i<=n;i++)
{
scanf("%d%d%d",&x,&y,&fa);
a[i].x=(double)x;
a[i].y=(double)y;
add1(i,fa);
add1(fa,i);
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (i!=j)
if (a[i].x==a[j].x&&a[i].y>a[j].y)
add2(i,j,sqrt((a[i].y-a[j].y)*2.0/10.0));
spfa();
printf("%0.2lf",dis[n]);
return 0;
}