【原创】【图论】Car的旅行路线

【NOIP2001】Car的旅行线路

时间限制: 1 Sec  内存限制: 64 MB
提交: 122  解决: 55

题目描述

又到暑假了,住在城市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位小数。

样例输入

Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

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


这道题目好坑好坑哒!!!!!!
让我们慢慢的一点一点的分析吧:
①:这明显是一道最短路径题目。
②:本题的难点莫过于已知矩形三个顶点坐标求第四个点了,下面让我们随便画个图分析分析。
【原创】【图论】Car的旅行路线_第1张图片

假设我们已经知道ABC三点坐标,要求D点坐标,怎么办呢?
【原创】【图论】Car的旅行路线_第2张图片

连接两条对角线,根据平行四边形对角线互相平分可得:O为AD中点,O也是BC中点。
根据中点坐标公式:P( (Xa+Xb)/2, (Ya+Yb)/2 )可得O点的坐标(如右上)。
那么我们就可以建立一个方程:
                                                
那么,移项可得:
                                             
同理,对于纵坐标:
                                               
那么,我们只需要确定哪个是A点就能算出D点坐标了(只确定B或C点是不行的,但是确定A点就可以了,因为剩下两点不需要考虑顺序,不需要考虑谁是B点,谁是C点)。
【原创】【图论】Car的旅行路线_第3张图片

容易发现,∠A是个直角,那么AB⊥AC,所以AB、AC的斜率之积为-1。因此,我们只需计算出AB、AC的斜率,再相乘即可。
即可?
【原创】【图论】Car的旅行路线_第4张图片
我们可以看到,A'B'确实垂直于A'C',但是它们乘积并不等于-1,所以需要特殊考虑。
③:计算出了所有飞机场的坐标后,就可以计算出所有路径要花的钱了。
同城的,就用距离乘以火车票钱;不是同城的,就用距离乘以飞机票钱。
④:用四次 Dijk或者 Floyd求出最短路径即可。
(只用一次Dijk也可以,但是你需要新建一个虚拟节点,把四个起点连起来)

详见代码:
#include
#include
#include
#include
using namespace std;
const int Da=9876543;
struct Epic
{
	int x,y;
}point[120][5];
int all,n,fly,walk,da,db;
double dis[420][420];
void fouth(int yx)
{
	int a,b,c,d=4;	
	//如何判断abc点->有两条垂线的是a点
	for(int i=1;i<=3;i++)
	{
		double k1,k2;//k1,k2:与另外两点的连线的斜率
		int p=i,q=-2,r;
		for(int j=1;j<=3;j++)//假设该点是A点,随机分配B点和C点
			if(q==-2 and i!=j) q=j;
			else if(q!=-2 and i!=j) r=j;
		//算斜率
		if(point[yx][p].x!=point[yx][q].x and point[yx][p].x!=point[yx][r].x)//不平行,不垂直
		{
			k1=(point[yx][p].y-point[yx][q].y)*1.0/(point[yx][p].x-point[yx][q].x);
			k2=(point[yx][p].y-point[yx][r].y)*1.0/(point[yx][p].x-point[yx][r].x);
			if(k1*k2>=-1.001 and k1*k2<=-0.999)
			{
				a=p,b=q,c=r;
				break;
			}
		}//p、r连线垂直于x轴,计算另一边的斜率是否为零
		else if(point[sx][p].x==point[yx][r].x)
		{
			if(point[yx][p].y-point[yx][q].y==0) 
			{
				a=p,b=q,c=r;
				break;
			}
		}//p、q连线垂直于x轴,计算另一边的斜率是否为0
		else 
		{
			if(point[yx][p].y-point[yx][r].y==0)
			{
				a=p,b=q,c=r;
				break;
			}
		}
	}//因为一定有一个直角,所以循环结束后,一定可以确定A,B,C的坐标
	point[yx][d].x=point[yx][b].x+point[yx][c].x-point[yx][a].x;
	point[yx][d].y=point[yx][b].y+point[yx][c].y-point[yx][a].y;
}
int main()
{
	scanf("%d",&all);
	while(all)
	{
		memset(point,0,sizeof point);
		for(int i=1;i<=4*n;i++)
			for(int j=1;i<=4*n;j++)
				dis[i][j]=(i!=j)*Da;
		scanf("%d %d %d %d",&n,&fly,&da,&db);
		for(int i=1;i<=n;i++)
		{
			scanf("%d %d %d %d %d %d %d",&point[i][1].x,&point[i][1].y,&point[i][2].x,&point[i][2].y,&point[i][3].x,&point[i][3].y,&walk);
			fouth(i);
			for(int j=1;j<=4;j++)//dis[j][k]:j号飞机场到k号飞机场的最短路
				for(int k=1;k<=4;k++)//注意一个城市有4个飞机场
					dis[4*(i-1)+j][4*(i-1)+k]=dis[4*(i-1)+k][4*(i-1)+j]=(j!=k)*(walk)*(sqrt((point[i][j].x-point[i][k].x)*(point[i][j].x-point[i][k].x)+(point[i][j].y-point[i][k].y)*(point[i][j].y-point[i][k].y)));
		}//以上为同城的坐火车的距离
		for(int i=1;i<=4*n;i++)
			for(int j=1;j<=4*n;j++)
				if(dis[i][j]==0 and i!=j)//飞机的距离
					dis[i][j]=fly*(sqrt((point[(i-1)/4+1][(i-1)%4+1].x-point[(j-1)/4+1][(j-1)%4+1].x)*(point[(i-1)/4+1][(i-1)%4+1].x-point[(j-1)/4+1][(j-1)%4+1].x)+(point[(i-1)/4+1][(i-1)%4+1].y-point[(j-1)/4+1][(j-1)%4+1].y)*(point[(i-1)/4+1][(i-1)%4+1].y-point[(j-1)/4+1][(j-1)%4+1].y)));
		for(int k=1;k<=4*n;k++)//弗洛伊德
			for(int i=1;i<=4*n;i++)
				for(int j=1;j<=4*n;j++)
					dis[i][j]=min(dis[i][j],dis[i][k]+dis[j][k]);
		double back=Da;
		for(int i=1;i<=4;i++)//比较四个起点到终点的最短距离
			for(int j=1;j<=4;j++)
				back=min(back,dis[(da-1)*4+i][(db-1)*4+j]);
		printf("%.2lf\n",back);
		all--;
	}
}

最后吐槽一句:本题代码量真的好大啊!




你可能感兴趣的:(#,心得,#,图论(树),#,题目,#,☆★★★★呐这是什么题,#,☠☠☠☠☠哼本人已死亡)