【RQNOJ86】智捅马蜂窝【最短路】

版权声明:若希望转载,在评论里直接说明即可,谢谢! https://blog.csdn.net/SSL_ZYC/article/details/83539984

题目大意:

题目链接:http://www.rqnoj.cn/problem/86
一个坐标系上有 n n 个点 n 1 n-1 条边,有两种移动方式:

  1. 经过一条边从一个点到达另一个点,耗时为这条边长度 ÷ v \div v
  2. 从一个点垂直跳下到达正下方的另一个点。耗时为 ( ( Y j Y i ) × 2 ÷ g ) \sqrt{((Y_j-Y_i)\times 2\div g)} (注意: g g 10 10

求从点 1 1 到点 n n 的最小时间。


思路:

对于移动方式 1 1 ,直接利用勾股求出两点之间的距离,然后建一条双向边。
对于移动方式 2 2 ,就枚举所有的点,判断他们是否满足 X i = X i X_i=X_i Y i > Y j Y_i>Y_j ,如果满足,那么就在 i i j j 中连一条单向边
然后跑个最短路就可以了。


代码:

#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;
}

猜你喜欢

转载自blog.csdn.net/SSL_ZYC/article/details/83539984