Description
自从小6学了最短路算法之后,就成了一个不折不扣的最短路理论拥护者,每次在校园里夜跑的时候,只要确定好起点和终点他就能快速算出最短的路径。然而小6却没有走过每一条路,只是对这些路径长度做了一个粗略估计,于是每条路就有了估计值与实际值的差距。小6想要知道从起点到终点,按照其中任意一条预估的最短路径跑,实际最长可能需要走过的路程。(因为同一长度的最短路可能有多个)
Input
多组输入,第一行是一个整数T,表示输入数据的组数(T≤20)。
接下来有T组数据,每组数据的第一行是四个整数N、M、S、E,分别代表图中的顶点数、边数、起点编号和终点编号。
(2≤N≤100, 1≤M≤1000, 1≤S,T≤N, S≠T)
之后的M行每行有四个整数u, v, a, b,代表图中编号为u的点到编号为v的点有一条双向边。
每条边有两个值a、b分别代表这条边的估计长度与实际长度。
(1≤u,v≤N, 1≤a,b≤1000, u ≠ v)
数据保证两个顶点间至多只有一条双向边相连,起点与终点间必定存在通路。
Output
对于每组输入,输出一行两个整数并换行,表示小6估算出的最短路长度以及实际最长可能需要走过的路程,两个整数间有一个空格。
Sample Input
22 1 1 21 2 3 43 3 1 31 2 2 31 3 3 42 3 1 2
Sample Output
3 43 5
题意::有一个图,图有两层,通过第一层的数据求所有的最短路。然后用第二层的权值计算第一层求得的最短路的最大权值。
刚开始看这道题就想到了记录路径的方式,但是究竟如何把多个路径记录下来呢?这里的确遇到了问题。在这里给出了用Floyd记录多重路径的 方法。
题解::
1)假设c【A】【B】数组中存放A,B两点的最短路,我们知道如果在c【A】【B】 == c【A】【C】+c【C】【B】,那么(A->C->B)也是一条最短路。所以我们可以用二维的vector记录中间节点C,既path【A】【B】.push_back(C)。
2)Floyd算法更新节点是在c【A】【B】 > c【A】【C】+c【C】【B】的时候。同样的如果满足该条件,那么path【A】【B】中存放的都将不是最短路,要进行clear()操作。
3)我们知道如果从A点到B点有N种最短路径,B点到C点有M种最短路径,那么从A经过B到C共有N*M种最短路径。(计算最短路有多少条)。
当把最短路都记录下来后还有一个问题,如何根据最短路求题中要求的最长路。
1)如果path【A】【B】为 空,那最长路肯定是d【A】【B】
2)如果path【A】【B】不为空,
1)假如有一条最短路A->C->B就分别求A C之间最长路,和B C之间的最长路。分别放入d【A】【C】,d【C】【B】。
2)比较d【A】【B】与d【A】【C】+d【C】【B】的大小。既d【A】【B】 = d【A】【B】>d【A】【C】+d【C】【B】? d【A】【B】:d【A】【C】+d【C】
【B】(C可能有多个。)
(用递归实现)
思路在经过细分析后也不是很难,哈哈哈。
代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
vector<ll> path[120][120];
ll c[120][120];
ll d[120][120];
ll max_load(int x,int y){
if(path[x][y].empty())
return d[x][y];
for(int i = 0;i<path[x][y].size();i++){
ll ans = path[x][y][i];
return max(d[x][y],max_load(ans,y)+max_load(x,ans));
}
}
int main(){
int T;
cin>>T;
while(T--){
for(int i = 0;i<120;i++)
for(int j = 0;j<120;j++)
path[i][j].clear();
int m,n,s,e;
cin>>n>>m>>s>>e;
int u,v,a,b;
for(int i = 0;i<n;i++)
for(int j = 0;j<n;j++)
c[i][j] = 2000;
for(int i = 0;i<n;i++)c[i][i] = 0;
for(int i = 0;i<m;i++){
cin>>u>>v>>a>>b;
u--;v--;
c[u][v] = a;c[v][u] = a;
d[u][v] = b;d[v][u] = b;
}
for (int k =0 ; k< n; k++)
{
for (int i = 0; i< n; i++){
for (int j = 0; j< n; j++)
if (c[i][j] > c[i][k] + c[k][j])
{
c[i][j] = c[i][k]+c[k][j];
path[i][j].clear();
path[i][j].push_back(k);
}
else if (c[i][j] == c[i][k] + c[k][j] && k!= i &&k !=j)
path[i][j].push_back(k);
}
}
cout<<c[s-1][e-1]<<" ";
cout<<max_load(s-1,e-1)<<endl;
}
return 0;
}
谢谢!