图论——所有点对间最短路径(多源最短路径)(例题精讲)

所有点对间最短路径(All Pairs Shortest Path,APSP):

一般来说,多源最短路径的求法为floyed。

floyed即为一个三维上的动态规划。

我们先引出最短路径的三角公式:

三角不等式:dist[p1][p2]<=dist[p1][p3]+dist[p3][p2]

可以结合下面的图想一下:

图论——所有点对间最短路径(多源最短路径)(例题精讲)_第1张图片

所有点对间最短路径的问题是指以图G=(V,E)为对象,求G中每个点之间的最短路径问题。

在解决APSP问题上,复杂度为O(V^3)的floyed算法广为人知。

for(int k=1;k<=N;k++){
		for(int i=1;i<=N;i++){
			for(int j=1;j<=N;j++){
				map[i][j]=min(map[i][j],map[i][k]+map[k][j]);//求出所有点对间最短路径 
			}
		}
	}

该算法需要注意map的初始值以及map[i][k]+map[k][j]的溢出问题。

下面给出一个精妙的例题:

 N个城市,每个城市有一匹马。第i座城市的马最多走Ei的距离,它的速度是
Si。第i座城市到第j座城市直接道路的长度为Dij,若Dij = −1则代表路不存在。
Q次询问,第Q次询问询问从Uk出发到Vk最少需要多少的时间。由于人没有腿不
能走路,所以人必须骑马,人每到一个城市可以换上那个城市的马继续前进。如
果在道路中间马走的距离用光了则会GG,骑着的马走到新的城市其能够走的距
离不会回复,每次询问一定存在至少一组解。
【输入格式】
第一行两个整数N,Q 。
接下来N行每行两个整数表示Ei, Si。
接下来N行每行N个整数表示Dij。
接下来Q行每行两个整数表示Uk,Vk。
【输出格式】
输出共Q行每行Q个整数表示答案。
【样例输入 1】
3 1
2 3
2 4
4 4
-1 1 -1
-1 -1 1
-1 -1 -1
1 3
【样例输出 1】
0.583333
【样例输入 2】
4 1
13 10
 1 1000
10 8
5 5
-1 1 -1 -1
-1 -1 1 -1
-1 -1 -1 10
-1 -1 -1 -1
1 4
【样例输出 2】
1.200000
【样例输入 3】
4 3
30 60
10 1000
12 5
20 1
-1 10 -1 31
10 -1 10 -1
-1 -1 -1 10
15 6 -1 -1
2 4
3 1
3 2
【样例输出 3】
0.510000
8.010000
8.000000
【数据规模与约定】
对于100%的数据, 1 ≤ N, M ≤ 100,1 ≤Ei ≤ 10^9, 1 ≤Si ≤ 1000,
 −1 ≤ Dij ≤10^9, Dii = −1, Dij ≠ 0, Vk ≠ Uk。
保证N ≤ 10。

首先我们需要求出一遍整个图的最短路。

然后用整个图的最短路来计算时间。

在把计算完的时间走一遍最短路。

问题就解决了。

当我们考虑换马的时候,就是floyed更新最短路的式子(仔细思考);

上代码:

#include
#include
#include
using namespace std;
int u,v,N,Q,k;
const int INF=0x3f3f3f3f;
double map[10001][10001],mintime[10001][10001];
double E[10001],S[10001];
double ans[10001];
int main(){
	cin>>N>>Q;
	for(int i=1;i<=N;i++){
		cin>>E[i]>>S[i];
	}
	for(int i=1;i<=N;i++){
		for(int j=1;j<=N;j++){
			cin>>k;
			map[i][j]=k;
			if(map[i][j]<0){
				map[i][j]=INF;
			}
			if(i==j) map[i][j]==0; 
		}
	}
	for(int k=1;k<=N;k++){
		for(int i=1;i<=N;i++){
			for(int j=1;j<=N;j++){
				map[i][j]=min(map[i][j],map[i][k]+map[k][j]);//求出所有点对间最短路径 
			}
		}
	}
	for(int k=1;k<=N;k++)
		for(int i=1;i<=N;i++)
			mintime[k][i]=INF;//把最短时间图初始化 
	for(int k=1;k<=N;k++)
		mintime[k][k]=0;
	for(int k=1;k<=N;k++)
		for(int i=1;i<=N;i++)
			if(map[k][i]<=E[k]) mintime[k][i]=map[k][i]/S[k];//如果马可以跑k到i的最短路 
	for(int k=1;k<=N;k++)
		for(int i=1;i<=N;i++)
			for(int j=1;j<=N;j++)
				mintime[i][j]=min(mintime[i][j],mintime[i][k]+mintime[k][j]);
	while(Q--){
		cin>>u>>v;	
		printf("%.6lf",mintime[u][v]);//直接查询 
	}
	return 0;
}

你可能感兴趣的:(图论————最短路)