【NOIP 2001提高组】Car的旅行路线(car.cpp)

Car的旅行线路(car.cpp)


题目描述
又到暑假了,住在城市A的Car想和朋友一起去城市B旅游。 她知道每个城市都有四个飞机场,分别位于一个矩形的四个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第I个城市中高速铁路了的单位里程价格为Ti,任意两个不同城市的机场之间均有航线,所有航线单位里程的价格均为t。 那么Car应如何安排到城市B的路线才能尽可能的节省花费呢?她发现这并不是一个简单的问题,于是她来向你请教。 任务: 找出一条从城市A到B的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少。


输入
第一行为一个正整数n(1≤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行,每行一个数据对应测试数据,结果保留2位小数。


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

    这道题题目描述极其恶心(所以理所当然与拯救公主一起进入了我的恶心题百科全书),那么我们一口一口地慢慢吃掉这个大胖子~

    1.我们很容易想到,第一步是算第四个点~那么如何计算呢?一开始我把此题想得很简单:矩形的话,知道三个坐标,就找相同的横坐标和纵坐标,然后把不与任何一个点相同的横坐标与纵坐标相组合,即可得到第四个点(我的描述有些难理解,可以看看图)

                

    但是,现实无情的打击了我……矩形还可以是这样的:

                 

    55555……只能重新思考了……其实呢,我们可以发现,三个点一定有一个是直角顶点,而另外两个顶点相加减去直角顶点,坐标刚好等于第四个点(可以去试试,没有错)!可是问题来了!怎么找直角顶点呢?其实,三个点能连成三条线,那么最长的一条线对面的那个点,就是直角顶点~

                 

    2.解决坐标后,什么都简单了~记录两点间费用,然后Floyed~

    3.没有3了~直接看代码吧~

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
struct node
{
	int x,y;
}City[105][5];
int mon[105];
double Mon[105][5][105][5];
double way(node a,node b)
{
	return sqrt(pow(a.x-b.x,2.0)+pow(a.y-b.y,2.0));
}
void four(int o)
{
	double p[4];
	int maxx;
	int maxn=0;
	for(int i=1;i<=2;i++)
	{
		for(int j=i+1;j<=3;j++)
		{
			p[6-i-j]=way(City[o][i],City[o][j]);
			if(p[6-i-j]>maxn)
			{
				maxn=p[6-i-j];
				maxx=6-i-j;
			}
		}
	}
	swap(City[o][maxx],City[o][1]);
	City[o][4].x=City[o][2].x+City[o][3].x-City[o][1].x;
	City[o][4].y=City[o][2].y+City[o][3].y-City[o][1].y;
}
int A,B,S,T,t;
double minn=1000000;
int main()
{
	//freopen("car.in","r",stdin);
	//freopen("car.out","w",stdout);
	scanf("%d",&t);
	for(;t;t--)
	{
		scanf("%d %d %d %d",&S,&T,&A,&B);
		for(int i=1;i<=S;i++)
		{
			for(int j=1;j<=3;j++)
			{
				scanf("%d %d",&City[i][j].x,&City[i][j].y);
			}
			scanf("%d",&mon[i]);
			four(i);
		}
		if(A==B)
		{
			printf("0.00\n");
			continue;
		}
		for(int i=1;i<=S;i++)
		{
			for(int j=1;j<=4;j++)
			{
				for(int k=1;k<=S;k++)
				{
					for(int l=1;l<=4;l++)
					{
						if(i==k)
						{
							Mon[i][j][k][l]=way(City[i][j],City[k][l])*mon[i];
						}
						else
						{
							Mon[i][j][k][l]=way(City[i][j],City[k][l])*T;
						}
					}
				}
			}
		}
		for(int i=1;i<=S;i++)
		{
			for(int in=1;in<=4;in++)
			{
				for(int j=1;j<=S;j++)
				{
					for(int jn=1;jn<=4;jn++)
					{
						for(int k=1;k<=S;k++)
						{
							for(int kn=1;kn<=4;kn++)
							{
								if(Mon[j][jn][i][in]+Mon[i][in][k][kn]<Mon[j][jn][k][kn])
								{
									Mon[j][jn][k][kn]=Mon[j][jn][i][in]+Mon[i][in][k][kn];
								}
							}
						}
					}
				}
			}
		}
		for(int i=1;i<=4;i++)
		{
			for(int j=1;j<=4;j++)
			{
				if(Mon[A][i][B][j]<minn)
				{
					minn=Mon[A][i][B][j];
				}
			}
		}
		printf("%.2lf\n",minn);
		minn=1000000;
	}
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值