洛谷P1027Car的旅行路线题解--zhengjun

题目描述

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

A_zjzj

图例(从上而下)

机场
高速铁路
飞机航线

注意:图中并没有标出所有的铁路与航线。

那么 C a r Car 应如何安排到城市B的路线才能尽可能的节省花费呢?她发现这并不是一个简单的问题,于是她来向你请教。

找出一条从城市 A A B B 的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少。

输入格式

第一行为一个正整数 n n ,表示有 n n 组测试数据。

每组的第一行有 4 4 个正整数 s , t , A , B s,t,A,B

S S 表示城市的个数, t t 表示飞机单位里程的价格, A A B B 分别为城市 A A B B 的序号。

接下来有 S S 行,其中第 i i 行均有 7 7 个正整数 x i 1 , y i 1 , x i 2 , y i 2 , x i 3 , y i 3 , T i x_{i1},y_{i1},x_{i2},y_{i2},x_{i3},y_{i3},T_i ,这当中的 ( x i 1 , y i 1 x_{i1},y_{i1} ),( x i 2 , y i 2 x_{i2},y_{i2} ),( x i 3 , y i 3 x_{i3},y_{i3} )分别是第 i i 个城市中任意 3 3 个机场的坐标, T i T_i 为第 i i 个城市高速铁路单位里程的价格。

输出格式

共有 n n 行,每行 1 1 个数据对应测试数据。
保留一位小数。

输入输出样例

输入 #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
输出 #1 复制
47.5

说明/提示

【数据范围】

对于 100 % 100\% 的数据, 1 n 10 1\le n \le 10 1 S 100 1\le S \le 100 1 A , B S 1\le A,B \le S

思路

一看就是最短路,我们可以把每个城市的一个机场看成一个点,然后算出所有机场之间的距离,然后就可以计算,最后用 S P F A SPFA 或者 d i j k s t r a dijkstra (因为一定没有负权边,我用的是 S P F A SPFA
但是,前面的预处理有点难度,可能裸的 S P F A SPFA 就不会有蓝色标签了。
首要的问题就是如何在知道一个矩阵中的 3 3 个点从而推出第 4 4 个点。

A_zjzj

就比如说这幅图假设我们已经知道了坐标为这些的点:

  1. x = 2   ,   y = 5 x=2\ ,\ y=5
  2. x = 5   ,   y = 1 x=5\ ,\ y=1
  3. x = 7   ,   y = 2 x=7\ ,\ y=2

那么我们怎么求第四个点呢。也就是 x = 4   ,   y = 6 x=4\ ,\ y=6

通过观察,我们发现:

一对对角线的 x x y y 的和就是另一对对角线的 x x y y 的和

所以,在给我们的 3 3 个点中,我们只要找到一对对角线,将它存在编号为 1 1 , 2 2 的点中,另一个点存在 3 3 号点中。

4 4 号点的坐标就是 ( x 1 + x 2 x 3 , y 1 + y 2 y 3 ) (x_1+x_2-x_3,y_1+y_2-y_3)

然后,问题就转换成了找一对对角线。

这还不简单,因为矩阵中的对角线一定是在这个矩阵内部最长的一条线之一(因为还有一条对角线)

所以,我们只要找到给我们的 3 3 个点中距离最大的 2 2 个点(运用勾股定律)

最后 S P F A SPFA 就不用我讲了吧( d f s dfs 还是 b f s bfs 随你,反正我喜欢 b f s bfs

代码

#include<bits/stdc++.h>
#define maxn 401
#define maxm 160001
#define bh(x,y) ((x-1)*4+y)//将第x个城市的第y个机场直接用四进制的方法转换成十进制(其实就是强制编号)
using namespace std;
int n,s,t,a,b;
struct zj{
	int x,y;
};
zj f[maxn][4];//存边,变量实在太多了,只好用f,一不小心重名了调死我了
int c[maxn];
int head[maxn],k,nex[maxm],to[maxm];
double v[maxm];
double d[maxm];
void add(int x,int y,double z){//链式前向星
	to[k]=y;
	v[k]=z;
	nex[k]=head[x];
	head[x]=k++;
}
int main(){
	cin>>n;
	while(n--){
		k=0;
		memset(head,-1,sizeof(head));
		//链表清空
		cin>>s>>t>>a>>b;
		for(int i=1;i<=s;i++){
			double x1,y1,x2,y2,x3,y3,maxx=0;
			int x,y;
			for(int j=0;j<3;j++)
			    cin>>f[i][j].x>>f[i][j].y;
			cin>>c[i];
			/*****************求第四条边****************/
			for(int j=0;j<3-1;j++){
				for(int l=j+1;l<3;l++){
					x=f[i][j].x-f[i][l].x;
					y=f[i][j].y-f[i][l].y;
					if(sqrt(double(x*x)+double(y*y))>maxx){//找距离最长的两个点
						x1=f[i][j].x;
						y1=f[i][j].y;
						x2=f[i][l].x;
						y2=f[i][l].y;
						x3=f[i][3-j-l].x;
						y3=f[i][3-j-l].y;
						maxx=sqrt(double(x*x)+double(y*y));
					}
				}
			}
			f[i][3].x=x1+x2-x3;
			f[i][3].y=y1+y2-y3;//套公式
			/**************************************************/
		}
		/*****************建边******************************************************/
		for(int i=1;i<=s;i++){
			for(int ii=1;ii<=s;ii++){
				for(int j=0;j<4;j++){
					for(int jj=0;jj<4;jj++){
						if(i==ii&&j==jj)
						    continue;
						double p=sqrt(double((f[i][j].x-f[ii][jj].x)*(f[i][j].x-f[ii][jj].x)+(f[i][j].y-f[ii][jj].y)*(f[i][j].y-f[ii][jj].y)));
						if(i!=ii)
						    add(bh(i,j),bh(ii,jj),p*t);
						else
						    add(bh(i,j),bh(ii,jj),p*c[i]);
					}
				}
			}
		}
		/**************初始化*********************************************************/
		queue<int> q;
		for(int i=0;i<s*4;i++)
		    d[i]=0x3fffffff;
		for(int i=0;i<4;i++){
		     q.push(bh(a,i));
		     d[bh(a,i)]=0;
		}
		/*************SPFA**********************************************************/
		while(!q.empty()){
			int x=q.front();
			q.pop();
			for(int pos=head[x];pos!=-1;pos=nex[pos]){
				if(d[to[pos]]>d[x]+v[pos]){
					d[to[pos]]=d[x]+v[pos];
					q.push(to[pos]);
				}
			}
		}
		/****************找答案*******************************************************/
		double ans=0x3fffffff;
		for(int i=0;i<4;i++)
		    if(d[bh(b,i)]<ans)
		    	ans=d[bh(b,i)];
		printf("%0.1lf",ans);
	}
    return 0;
}

谢谢–zhengjun

发布了48 篇原创文章 · 获赞 49 · 访问量 2142

猜你喜欢

转载自blog.csdn.net/A_zjzj/article/details/104694225
今日推荐