ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-06-10 19:02:33  阅读:166  来源: 互联网

标签:head le 洛谷 -- 题解 城市 对角线 int double


题目描述

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

A_zjzj

图例(从上而下)

机场
高速铁路
飞机航线

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

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

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

输入格式

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

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

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

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

输出格式

共有 \(n\) 行,每行 \(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\%\) 的数据,\(1\le n \le 10\),\(1\le S \le 100\),\(1\le A,B \le S\)

思路

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

A_zjzj

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

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

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

通过观察,我们发现:

一对对角线的 \(x\) 和 \(y\) 的和就是另一对对角线的 \(x\) 和 \(y\) 的和

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

则 \(4\) 号点的坐标就是 \((x_1+x_2-x_3,y_1+y_2-y_3)\)

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

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

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

最后 \(SPFA\) 就不用我讲了吧(\(dfs\) 还是 \(bfs\) 随你,反正我喜欢 \(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

标签:head,le,洛谷,--,题解,城市,对角线,int,double
来源: https://www.cnblogs.com/A-zjzj/p/16364393.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有