【NOIP2001提高组】Car的旅行路线

题目背景

NOIP2001提高组第四题。

题目描述

又到暑假了,住在城市 A 的 Car 想和朋友一起去城市 B 旅游。她知道每个城市都有四个飞机场,分别位于一个矩形的四个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第I个城市中高速铁路了的单位里程价格为 Ti,任意两个不同城市的机场之间均有航线,所有航线单位里程的价格均为 t。
图例:

《【NOIP2001提高组】Car的旅行路线》

那么 Car 应如何安排到城市 B 的路线才能尽可能的节省花费呢?请你编程帮她找出一条从城市 A 到 B 的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少,小数点后保留 2 位。

输入格式

第一行为一个正整数 n(0<=n<=10),表示有 n 组测试数据。
每组的第一行有四个正整数 s,t,A,B。其中 s(0<s<=100)表示城市的个数,t 表示飞机单位里程的价格,A,B 分别为城市 A,B 的序号(1<=A,B<=s)。
接下来有 s 行,其中第 i 行均有 7 个正整数 xi1,yi1,xi2,yi2,xi3,yi3 和 Ti,其中的 (xi1,yi1),(xi2,yi2),(xi3,yi3) 分别是第 i 个城市中任意三个机场的坐标,Ti为第 i 个城市高速铁路单位里程的价格。

输出格式

输出共有 n 行,每行一个数据对应相应测试数据的输出结果,即总的最小花费。

样例数据 1

输入

1

3 10 1 3

1 1 1 3 3 1 30

2 5 7 4 5 2 1

8 6 8 8 11 6 3

输出

47.55

 

解析:
       最短路。

     最短路很明显,只需要细心一点就行了,唯一需要说一下的就是对于输入的每个城市的三个机场,如何求出第四个机场的坐标?

       因为保证是矩形,所以只需要通过向量法求出两个直角边,就可以确定矩形了。

 

代码:
 

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;

const int Maxn=405;
const int Maxm=220000;
int q,n,size,S,T;
int first[Maxn],vis[Maxn];
double ans=1e9,m,dis[Maxn],t[Maxn],x[Maxn],y[Maxn];
struct shu{int to,next;double len;};
shu edge[Maxm<<1];

inline int get_int()
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') f=-1,c=getchar();
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}

inline void clean()
{
	size=0;
	for(int i=1;i<=n*4;i++) first[i]=0;
}

inline void cal(int id,double x1,double y1,double x2,double y2,double x3,double y3)
{
	x[(id-1)*4+4]=x1+x3-x2;
	y[(id-1)*4+4]=y1+y3-y2;
}

inline void Q(int id)
{
	double x1=x[(id-1)*4+1],y1=y[(id-1)*4+1];
	double x2=x[(id-1)*4+2],y2=y[(id-1)*4+2];
	double x3=x[(id-1)*4+3],y3=y[(id-1)*4+3];
    if((x1-x2)*(x3-x2)+(y1-y2)*(y3-y2)==0) cal(id,x1,y1,x2,y2,x3,y3);
	if((x1-x3)*(x2-x3)+(y1-y3)*(y2-y3)==0) cal(id,x1,y1,x3,y3,x2,y2);
	if((x3-x1)*(x2-x1)+(y3-y1)*(y2-y1)==0) cal(id,x3,y3,x1,y1,x2,y2);
}

inline double calc(int i,int j)
{
	return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}

inline void build(int x,int y,double z)
{
	edge[++size].next=first[x];
	first[x]=size;
	edge[size].to=y,edge[size].len=z;
}

inline void pre()
{
	for(int i=1;i<=n;i++)
	{
	  for(int j=1;j<=4;j++)
	    for(int k=1;k<=4;k++)
	    {
	      if(j==k) continue;
	      double len=calc((i-1)*4+j,(i-1)*4+k)*t[i];
	      build((i-1)*4+j,(i-1)*4+k,len);
	    }
	  for(int j=1;j<=n;j++)
	  {
	  	if(i==j) continue;
	  	for(int k=1;k<=4;k++)
	  	  for(int l=1;l<=4;l++)
	  	  {
	  		double len=calc((i-1)*4+k,(j-1)*4+l)*m;
	  	  	build((i-1)*4+k,(j-1)*4+l,len);
	  	  }
	  }
	}
}

inline double mn(double x,double y){return x<y?x:y;}

inline void dijkstra(int s)
{
	memset(vis,0,sizeof(vis));
	priority_queue<pair<double,int> >q;
	q.push(make_pair(0.0,s));dis[s]=0.0;
	while(q.size())
	{
	  int point=q.top().second;q.pop();
	  if(vis[point]) continue;vis[point]=1;
	  for(int u=first[point];u;u=edge[u].next)
	  {
	  	int to=edge[u].to;
	  	if(dis[to]>dis[point]+edge[u].len)
	  	{
	  	  dis[to]=dis[point]+edge[u].len;
	  	  q.push(make_pair(-dis[to],to));
	  	}
	  }
	}
}

inline void solve()
{
	for(int i=1;i<=4;i++)
	{
	  for(int j=1;j<=n*4;j++) dis[j]=1e9;
	  dijkstra((S-1)*4+i);
	  for(int j=1;j<=4;j++) ans=mn(ans,dis[(T-1)*4+j]);
	}
}

int main()
{
	q=get_int();
	while(q--)
	{
	  n=get_int(),m=get_int(),S=get_int(),T=get_int();
	  clean();
	  for(int i=1;i<=n;i++)
	  {
	  	for(int j=1;j<=3;j++) x[(i-1)*4+j]=get_int(),y[(i-1)*4+j]=get_int();
	  	Q(i);
	  	t[i]=get_int();
	  }
	  pre();
	  solve();
	  printf("%.2lf\n",ans);
	}
	return 0;
}

 

    原文作者:旅游交通路线问题
    原文地址: https://blog.csdn.net/m0_38083668/article/details/82919075
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞