洛谷P1027 Car的旅行路线(spfa) 题解

94 篇文章 0 订阅

题目来源:

点击打开链接

题目描述:

题目描述

又到暑假了,住在城市 AA 的 CarCar 想和朋友一起去城市 BB 旅游。她知道每个城市都有 44 个飞机场,分别位于一个矩形的 44 个顶点上,同一个城市中 22 个机场之间有 11 条笔直的高速铁路,第 II 个城市中高速铁路了的单位里程价格为 T_iTi ,任意两个不同城市的机场之间均有航线,所有航线单位里程的价格均为 tt 。

图例(从上而下)

机场
高速铁路
飞机航线

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

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

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

输入输出格式

输入格式:

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

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

SS ( 0<S \le 1000<S100 )表示城市的个数, tt 表示飞机单位里程的价格, AA , BB 分别为城市 AA , BB 的序号,( 1 \le A1A, B \le SBS )。

接下来有 SS 行,其中第 II 行均有 77 个正整数 xi_1,yi_1,xi_2,yi_2,xi_3,yi_3,Tixi1,yi1,xi2,yi2,xi3,yi3,Ti ,这当中的( xi_1,yi_1xi1,yi1 ),( xi_2,yi_2xi2,yi2),( xi_3,yi_3xi3,yi3 )分别是第 ii 个城市中任意 33 个机场的坐标, TiTi 为第 ii 个城市高速铁路单位里程的价格。

输出格式:

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

输入输出样例

输入样例#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








解题思路:

       这题是一个最短路的裸题,关键还是怎样把所有边存起来,首先是它只输入每个城市的3个点,所以要先把第三个点算出来,可以用x,y的偏移量算。接下来就是存边,因为高速和航线的价格不同,所以要分开储存。存完之后就可以用spfa,因为求得是两个城市之间的距离,所以我用了4次spfa,分别储存起点机场到终点机场的距离,机场编号我是1-4,5-8。。这样存的,最后算出所有距离的最小值就行。

代码:

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
double min(double x,double y)
{
	if(x>y)return y;
	return x;
}
struct newt{
	int dian[5][2];
	int fy;
}cs[1005];
bool vis[100000];
double dis[4][100000];
vector<pair<int,double> >E[1000005];
queue<int>q;
double js(int x1,int y1,int x2,int y2)//计算距离 
{
	return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
void xz(int id,int x1,int y1,int x2,int y2,int x3,int y3)//已知3点求第四个点 
{
	int x4,y4;
	if((x1-x2)*(x2-x3)+(y1-y2)*(y2-y3)==0){
		x4=x1-x2+x3;
		y4=y1-y2+y3;
		cs[id].dian[4][0]=x4;
		cs[id].dian[4][1]=y4;
	}
	else if((x1-x2)*(x1-x3)+(y1-y2)*(y1-y3)==0){
		x4=x2-x1+x3;
		y4=y2-y1+y3;
		cs[id].dian[4][0]=x4;
		cs[id].dian[4][1]=y4;
	}
	else{
		x4=x1-x3+x2;
		y4=y1-y3+y2;
		cs[id].dian[4][0]=x4;
		cs[id].dian[4][1]=y4;
	}
	return ;
}
int main()
{
	int t;
	cin>>t;
	while(t--){
		int n,cost,X,Y;
		cin>>n>>cost>>X>>Y;
		for(int i=1;i<=n;i++)
		{
			int a,b,c,d,e,f;
			cin>>a>>b>>c>>d>>e>>f>>cs[i].fy;
			cs[i].dian[1][0]=a;
			cs[i].dian[1][1]=b;
			cs[i].dian[2][0]=c;
			cs[i].dian[2][1]=d;
			cs[i].dian[3][0]=e;
			cs[i].dian[3][1]=f;
			xz(i,a,b,c,d,e,f);
			for(int j=1;j<=3;j++)
			for(int k=j+1;k<=4;k++)//每个城市内的边 
			{
				double jl=js(cs[i].dian[j][0],cs[i].dian[j][1],cs[i].dian[k][0],cs[i].dian[k][1])*cs[i].fy;
				E[j+(i-1)*4].push_back(make_pair(k+(i-1)*4,jl));
				E[k+(i-1)*4].push_back(make_pair(j+(i-1)*4,jl));
			}
		}
		for(int i=1;i<n;i++)
		for(int j=i+1;j<=n;j++)//每两个城市之间的边 
		{
			for(int k=1;k<=4;k++)
			for(int s=1;s<=4;s++)
			{
				//cout<<k+(i-1)*4<<" "<<s+(j-1)*4<<endl;
				double jl=js(cs[i].dian[k][0],cs[i].dian[k][1],cs[j].dian[s][0],cs[j].dian[s][1])*cost;
				E[k+(i-1)*4].push_back(make_pair(s+(j-1)*4,jl));
				E[s+(j-1)*4].push_back(make_pair(k+(i-1)*4,jl));
			}
		}
//		for(int i=1;i<=n*4;i++)
//		for(int j=0;j<E[i].size();j++)
//		cout<<i<<" "<<E[i][j].first<<" "<<E[i][j].second<<endl;
		int qd[4];
		for(int i=0;i<4;i++)
		for(int j=0;j<=10000;j++)
		dis[i][j]=1e9;
		for(int i=0;i<4;i++)
		qd[i]=(X-1)*4+(i+1);
		for(int i=0;i<4;i++)
		{
			memset(vis,0,sizeof(vis));
			q.push(qd[i]);
			vis[qd[i]]=1;
			dis[i][qd[i]]=0;
			while(!q.empty())
			{
				int now=q.front();q.pop();
				vis[now]=0;
				for(int j=0;j<E[now].size();j++)
				{
					int v=E[now][j].first;
					//cout<<dis[i][v]<<" "<<dis[i][now]<<" "<<E[now][j].second<<endl;
					if(dis[i][v]>dis[i][now]+E[now][j].second)
					{
						dis[i][v]=dis[i][now]+E[now][j].second;
						if(!vis[v]){
							vis[v]=1;
							q.push(v);
						}
					}
				}
			}
//			for(int j=1;j<=n*4;j++)
//			cout<<dis[i][j]<<" ";
//			cout<<endl;	
		}
		double Min=1e9;
		for(int i=0;i<4;i++)
		{
			for(int j=(Y-1)*4+1;j<=(Y-1)*4+4;j++)
			{
				//cout<<i<<" "<<j<<" "<<dis[i][j]<<endl;
				if(dis[i][j]<Min){
					Min=dis[i][j];
				}
			}
		}
		printf("%.1lf\n",Min);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值