旅行路线(单源最短路(Dijkstra))

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


  任务:找出一条从城市A到B的旅游路线,出发和到达城市中的机场可以任意选取,要求总的花费最少。 
 
【输入格式】
 
  第一行有一个整数K,表示有K组数据
  第二行有四个正整数s,t,A,B。S(0   接下来有S行,其中第i行均有7个正整数x1,y1,x2,y2,x3,y3,T,这当中的(x1,y1),(x2,y2),(x3,y3)分别是第i个城市中任意三个机场的坐标,T 为第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
 
【数据范围】
 

0

 

分析:

        这个题模板很直观,可能卡也就卡在找第四个直角上。

        建图顺带一提,首先,同一个矩形内只能连高速铁路;其次,不同的矩形之间连接飞机航线;

        还是得说说找第四个直角的方法,我是通过斜率的公式来找的:枚举这三个点把哪个当做直角,设三个角A,B,C,其中C是第四个直角,然后根据斜率的公式分别算出直线AC和直线AB的斜率,然后看相乘是不是等于-1.....可以自己推一推,其实高中也会讲;注意的是,当这个矩形的边与x轴,y轴平行时注意斜率为0和斜率不存在的情况(分母为0)感觉应该可以有更简便的方法...

        然后连好之后,在起点的矩形四个角上分别做一次最短路算法,求最小的就可以了。

 

在确定直角的时候可以自己打一下草稿

#include
#include
#include
#include
using namespace std;
typedef double DB;
const int maxn=105;
const DB INF=100000000;
int K,s,t,n,A,B,np,last[maxn*4],cost[maxn];
struct edge{int to,pre;DB w;}E[maxn*4*maxn*4]; 
struct point{int x,y;}P[maxn*4];
struct data
{
	DB d;int id;
	friend bool operator < (data a,data b) {return a.d>b.d;}
};

char c;
inline void qkscanf(int &x)
{
	for(c=getchar();c<'0'||c>'9';c=getchar());
	for(x=0;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
}

inline void init()
{
	for(int i=1;i<=n*4;i++) last[i]=0;
	n=0,np=0;
}

inline bool check(point a,point b,point c) 
{
	if((a.y==c.y&&b.x==c.x)||(a.x==c.x&&b.y==c.y)) return 1;//有一条直线与坐标轴平行 
	if(a.y==c.y||a.x==c.x||b.x==c.x||b.y==c.y) return 0;//如果一条直线与坐标轴平行但另一条不平行,行不通 
	return (a.x-c.x)*(b.x-c.x)/(a.y-c.y)/(b.y-c.y)==-1;//两个斜率相乘为-1 
}

inline point findp(point a,point b,point c)
{
	int x=a.x+b.x-c.x,y=a.y+b.y-c.y;//如果已知c是直角,那么有Xa+Xb=Xc+Xd,Y类似 
	return (point){x,y};
} 

inline DB DIST(int a,int b,int k)
{
	DB dis=sqrt((DB)(P[a].x-P[b].x)*(P[a].x-P[b].x)+(DB)(P[a].y-P[b].y)*(P[a].y-P[b].y));
	return dis*(DB)k;
} 

inline void addedge(int u,int v,DB dis)
{
	E[++np]=(edge){v,last[u],dis};
	last[u]=np;
}

int done[maxn*4];
DB dist[maxn*4];
inline void Dijkstra(int s)
{
	priority_queuepq;
	for(int i=0;i<=n;i++) done[i]=0,dist[i]=INF;
	dist[s]=0;
	pq.push((data){0,s});
	while(!pq.empty())
	{
		data t=pq.top();pq.pop();
		int i=t.id;
		if(done[i]) continue;
		done[i]=1;
		for(int p=last[i];p;p=E[p].pre)
		{
			int j=E[p].to;
			DB w=E[p].w;
			if(dist[j]>dist[i]+w)
			{
				dist[j]=dist[i]+w;
				pq.push((data){dist[j],j}); 
			}
		} 
	}
}

int main()
{
//	freopen("in.txt","r",stdin);
	qkscanf(K);
	while(K--)
	{
		qkscanf(s);qkscanf(t);qkscanf(A);qkscanf(B);
		init();
		int T;
		point a1,a2,a3,a4;
		for(int i=1;i<=s;i++)//先把每个点存起来 
		{
			qkscanf(a1.x);qkscanf(a1.y);
			qkscanf(a2.x);qkscanf(a2.y);
			qkscanf(a3.x);qkscanf(a3.y);
			P[n++]=a1,P[n++]=a2,P[n++]=a3;
			if(check(a1,a2,a3)) a4=findp(a1,a2,a3);
			else if(check(a1,a3,a2)) a4=findp(a1,a3,a2);
			else a4=findp(a2,a3,a1);
			P[n++]=a4;
			qkscanf(cost[i]);
		}
		register int a,b;
		for(int i=1;i<=s;i++)//注意建边 
		{
			for(int k1=0;k1<4;k1++)
			{
				a=(i-1)*4+k1;
				for(int k2=k1+1;k2<4;k2++)
				{
					b=(i-1)*4+k2;
					DB dis=DIST(a,b,cost[i]);
					addedge(a,b,dis);
					addedge(b,a,dis);
				}
				
				for(int j=i+1;j<=s;j++)
				{
					for(int k2=0;k2<4;k2++)
					{
						b=(j-1)*4+k2;
						DB dis=DIST(a,b,t);
						addedge(a,b,dis);
						addedge(b,a,dis); 
					}
				}
			}
		}
		
		DB ans=INF;
		for(int i=0;i<4;i++)
		{
			int s=(A-1)*4+i;
			Dijkstra(s);
			for(int j=0;j<4;j++)
			{
				int k=(B-1)*4+j;
				ans=min(ans,dist[k]);
			}
		}
		
		printf("%.2llf\n",ans);
	} 
	
	return 0;
}

 

 

 

  

你可能感兴趣的:(图论-最短路问题)