【NOIP2001】Car的旅行线路
题目描述
又到暑假了,住在城市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
最开始,让我烧脑的就是怎么求第4个机场的坐标。后来发现,在一个平面直角坐标系的矩形中,一个顶点的坐标就是两个相邻点的坐标之和减去对点的坐标。举一个例子:
A(1,2),B(2,4),C(3,1),那么D点就是(B的坐标+C的坐标-A的坐标):
XD=2+3-1=4;YD=4+1-2=3;∴D(4,3)。
可是要这样的话我们必须还要判断3个点中哪两个点是第4个点的相邻点。我们先在刚才那个矩形中不看D点,然后把A,B,C连成一个Rt△,发现A点就是直角顶点,而我们在刚才计算过程中所减去的对角就是A,所以得出一个结论:
三个点中的直角顶点就是需要减去的那个对点。
所以再初始化每个机场之间的距离,用两点间距离公式——
A(x1,y1),B(x2,y2)之间AB=√(x1-x2)²+(y1-y2)²
然后再把每个距离来乘飞机的单价或高速铁路的单价。这里要注意一个判断两机场是否在同一城市时。不能用
if(i/4==j/4) dis[i][j]*=lufei[i/4];
因为比如i为3、j为4时,i/4≠j/4。所以要用
if((i-1)/4==(j-1)/4) dis[i][j]*=lufei[(i-1)/4+1];
这样就不会判断错误了。
最后再用Floyed(随便,根据自己喜好)来搜就行了。
代码如下:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
using namespace std;
int t,s,p,A,B,x,xx,xxx,y,yy,yyy,xd,yd,m,n,xxxx[401],yyyy[401],lu[101];
double dis[401][401];
void Z(int xa ,int xb ,int xc ,int ya ,int yb ,int yc)
{
double ab=(xa-xb)*(xa-xb)+(ya-yb)*(ya-yb);
double ac=(xa-xc)*(xa-xc)+(ya-yc)*(ya-yc);
double bc=(xb-xc)*(xb-xc)+(yb-yc)*(yb-yc);
if(ab+ac==bc)//bc为斜边,A为对角
{
xd=xb+xc-xa;
yd=yb+yc-ya;
return ;
}
if(ab+bc==ac)//ac为斜边,B为对角
{
xd=xa+xc-xb;
yd=ya+yc-yb;
return ;
}
if(ac+bc==ab)//ab为斜边,C为对角
{
xd=xa+xb-xc;
yd=ya+yb-yc;
return ;
}
}
void Dis()
{
for(int i=n+1;i<=n+4;i++) dis[i][i]=0;//先更新同一个城市的距离
dis[n+1][n+2]=dis[n+2][n+1]=sqrt((x-xx)*(x-xx)+(y-yy)*(y-yy));
dis[n+1][n+3]=dis[n+3][n+1]=sqrt((x-xxx)*(x-xxx)+(y-yyy)*(y-yyy));
dis[n+1][n+4]=dis[n+4][n+1]=sqrt((x-xd)*(x-xd)+(y-yd)*(y-yd));
dis[n+2][n+3]=dis[n+3][n+2]=sqrt((xx-xxx)*(xx-xxx)+(yy-yyy)*(yy-yyy));
dis[n+2][n+4]=dis[n+4][n+2]=sqrt((xx-xd)*(xx-xd)+(yy-yd)*(yy-yd));
dis[n+3][n+4]=dis[n+4][n+3]=sqrt((xxx-xd)*(xxx-xd)+(yyy-yd)*(yyy-yd));
}
void Y()
{
for(int u=1;u<=s*4;u++)
{
for(int v=1;v<=s*4;v++)
{
if((u-1)/4==(v-1)/4)//同一个城市
dis[u][v]*=lu[(u-1)/4+1];
else//不同城市
{
dis[u][v]=sqrt((xxxx[u]-xxxx[v])*(xxxx[u]-xxxx[v])+(yyyy[u]-yyyy[v])*(yyyy[u]-yyyy[v]))*p;
}
}
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
memset(dis,0x7f,sizeof(dis));
memset(xxxx,0,sizeof(xxxx));
memset(yyyy,0,sizeof(yyyy));
memset(lu,0,sizeof(lu));
n=0;
scanf("%d%d%d%d",&s,&p,&A,&B);
if(A==B){printf("0.00
");continue;}
for(int ll=1;ll<=s;ll++)
{
scanf("%d %d %d %d %d %d %d",&x,&y,&xx,&yy,&xxx,&yyy,&m);lu[ll]=m;
Z(x,xx,xxx,y,yy,yyy);
Dis();
xxxx[++n]=x;yyyy[n]=y;//存点坐标
xxxx[++n]=xx;yyyy[n]=yy;
xxxx[++n]=xxx;yyyy[n]=yyy;
xxxx[++n]=xd;yyyy[n]=yd;
}
Y();
for(int k=1;k<=s*4;k++)//Floyed
for(int i=1;i<=s*4;i++)
for(int j=1;j<=s*4;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
double k=1<<30;
for(int i=1;i<=4;i++)//两个城市的每个机场到每个机场的距离找最小的
for(int j=1;j<=4;j++)
k=min(k,dis[(A-1)*4+i][(B-1)*4+j]);
printf("%.2lf
",k);
}
}