[NOIP2001 提高组] Car 的旅行路线 题解

题目描述

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

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

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

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

输入格式

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

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

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

接下来有 S 行,其中第 ii 行均有 77 个正整数xi1,yi1,xi2,yi2,xi3,yi3,Ti​,这当中的 (xi1,yi1),(xi2,yi2),(xi3,yi3),分别是第 ii 个城市中任意 33 个机场的坐标,TiTi​ 为第 ii 个城市高速铁路单位里程的价格。

输出格式

共有 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

分析:

注:这里面的点指机场而非城市

这道题乍一看题目描述不难,其实就是一个最短路问题,不过就是起点可能有多个,终点也有多个,所以我们跑个Floyd就行。

  • 但因为我怕O(n3)跑不起,所以换成了n遍dijkstra(这里n☞点数)

所以时间复杂度为:O(n2logn)

  • (dij用了堆优化

然后我们来到样例,发现还有毒瘤的预处理。

样例无良的给了矩形的三个点,说明第四个点可以根据前三个求出。

  • 于是我们考虑到运用矩形对角线的一些性质。

  • 首先找出距离最远的两个点(三个点中)

  • 然后连线取中点(当然编程中不用连线那一步操作)

  • 再将另外的第3个点(不在连线的两端)向中点连线,延长即可

void find(double a,double b,double c,double d,double e,double f)//读入三个点的坐标,跑完函数就把第四个点的值赋完了
{
	cnt++;
	dis[1].num=sqrt(Sqr(a-c)+Sqr(b-d)); 
	dis[1].id=1;
	dis[2].num=sqrt(Sqr(e-c)+Sqr(f-d)); 
	dis[2].id=2;
	dis[3].num=sqrt(Sqr(a-e)+Sqr(b-f));
	dis[3].id=3;
	sort(dis+1,dis+4,cmp);
	if(dis[1].id==1)
	{
		double x=min(a,c)+Abs(a-c)/2;
		double y=min(b,d)+Abs(b-d)/2;
		double xn=x+x-e;
		double yn=y+y-f;
		p[cnt].x=xn;
		p[cnt].y=yn;
	}
	if(dis[1].id==2)
	{
		double x=min(c,e)+Abs(e-c)/2;
		double y=min(f,d)+Abs(f-d)/2;
		double xn=x+x-a;
		double yn=y+y-b;
		p[cnt].x=xn;
		p[cnt].y=yn;
	}
	if(dis[1].id==3)
	{
		double x=min(a,e)+Abs(a-e)/2;
		double y=min(b,f)+Abs(b-f)/2;
		double xn=x+x-c;
		double yn=y+y-d;
		p[cnt].x=xn;
		p[cnt].y=yn;
	}
}

这样,就处理完了,最后,我们发现其实任意两点都有连接(要不航线要不铁路),所以处理出距离,在判断是否在一个城市,就可以找到每条路的价值。

  • 跑dij即可

  • 别忘了给点所在的城市打标记,这样最后方便找A和B

这里引申出了一个惨痛的教训:结构体的存储方式要想好

刚开始我是以一个城市为一个结构体,然后就特别难写,最后只好重构代码

code:

#include<cstdio>
#include<cmath>
#include<map>
#include<cstring>
#include<queue> 
#include<algorithm>
using namespace std;
#define pa pair<double,int>
int vis[4005];
priority_queue<pa,vector<pa>,greater<pa> > q;
struct point
{
	double x,y,T;
	int id;
}p[4005];
struct D
{
	double id;
	double num;
}dis[4];
double Sqr(int x)
{
	return x*x;
}
double cmp(const D &a,const D &b)
{
	return a.num>b.num;
}
double Abs(double x)
{
	if(x<0)return -x;
	return x;
}
int cnt=0;
void find(double a,double b,double c,double d,double e,double f)
{
	cnt++;
	dis[1].num=sqrt(Sqr(a-c)+Sqr(b-d)); 
	dis[1].id=1;
	dis[2].num=sqrt(Sqr(e-c)+Sqr(f-d)); 
	dis[2].id=2;
	dis[3].num=sqrt(Sqr(a-e)+Sqr(b-f));
	dis[3].id=3;
	sort(dis+1,dis+4,cmp);
	if(dis[1].id==1)
	{
		double x=min(a,c)+Abs(a-c)/2;
		double y=min(b,d)+Abs(b-d)/2;
		double xn=x+x-e;
		double yn=y+y-f;
		p[cnt].x=xn;
		p[cnt].y=yn;
	}
	if(dis[1].id==2)
	{
		double x=min(c,e)+Abs(e-c)/2;
		double y=min(f,d)+Abs(f-d)/2;
		double xn=x+x-a;
		double yn=y+y-b;
		p[cnt].x=xn;
		p[cnt].y=yn;
	}
	if(dis[1].id==3)
	{
		double x=min(a,e)+Abs(a-e)/2;
		double y=min(b,f)+Abs(b-f)/2;
		double xn=x+x-c;
		double yn=y+y-d;
		p[cnt].x=xn;
		p[cnt].y=yn;
	}
}
double d[405][405],dist[405][405];
void dijkstra(int s)
{
	memset(vis,0,sizeof(vis));
	d[s][s]=0;
    q.push(make_pair(0,s));
    while(!q.empty())
    {
        int x=q.top().second;
        q.pop();
        if(vis[x]==1)
        continue;
        vis[x]=1;
        for(int i=1;i<=cnt;i++)
        {
            if(d[s][x]+dist[x][i]<d[s][i])
            {
                d[s][i]=d[s][x]+dist[x][i];
                q.push(make_pair(d[s][i],i));
            }
        }
    }
}
int main()
{
	double t;
	int N,A,B,s;
	scanf("%d",&N);
	while(N--)
	{
		cnt=0;
		scanf("%d%lf%d%d",&s,&t,&A,&B);
		int city=0;
		for(int i=1;i<=s;i++)
		{
			city++;
			for(int j=1;j<=3;j++)
			{
				cnt++;
				scanf("%lf%lf",&p[cnt].x,&p[cnt].y);
				p[cnt].id=city;
			}
			scanf("%lf",&p[cnt].T);
			p[cnt-2].T=p[cnt].T;
			p[cnt-1].T=p[cnt].T;
			p[cnt+1].T=p[cnt].T;
			//printf("%lf %lf\n",p[cnt-j+1].x,p[cnt-j+1].y);
			find(p[cnt-2].x,p[cnt-2].y,p[cnt-1].x,p[cnt-1].y,p[cnt].x,p[cnt].y);
			p[cnt].id=city;
			//printf("i=%lf %lf\n",p[cnt].x,p[cnt].y);
		}
		for(int i=1;i<=cnt;i++)
		{
			for(int j=1;j<=cnt;j++)
			{
				double tmp=sqrt(Sqr(p[i].x-p[j].x)+Sqr(p[i].y-p[j].y));
				if(p[i].id==p[j].id)
				{
					dist[i][j]=tmp*p[i].T;
				}
				else
				{
					dist[i][j]=tmp*t;
				}
			}
		}
		for(int i=1;i<=cnt;i++)
		{
			for(int j=1;j<=cnt;j++)
			{
				d[i][j]=2147483640;
			}
		}
		for(int i=1;i<=cnt;i++)
		{
			dijkstra(i);
		}
		double ans=2147483640;
		for(int i=1;i<=cnt;i++)
		{
			for(int j=1;j<=cnt;j++)
			{
				if(p[i].id==A&&p[j].id==B)
				{
					if(d[i][j]<ans)
					{
						ans=d[i][j];
					}
					//ans=min(ans,d[i][j]);
				}
			}
		}
		printf("%.1lf\n",ans);
	}		
	return 0;
}

在百忙之中写一篇题解也比较辛苦,别忘了点个赞! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值