1. 程式人生 > >【RQNOJ86】智捅馬蜂窩【最短路】

【RQNOJ86】智捅馬蜂窩【最短路】

題目大意:

題目連結: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;
}