旅行(堆优化版dijkstra)
题目:旅行
题目链接:https://ac.nowcoder.com/acm/problem/14550
题意:给出n个点和m条边,小z从一点走到另一个点总是走最短路径。找到一个起点,一个中转点和一个终点(三点各不相同), 使得小z从起点到中转点,再从中转点到终点的路程最远,求该最远路程。
输入:第一行输入测试用例个数t。
t 个测试用例。每个测试用例第一行输入n和m(3 <= n, m <= 1000)。
接下来m行,每行三个整数a, b, (1 <= a, b <= n) c,(1 <= c <= 100)表示点a和点b之间有一条长为c的无向边。
输出:输出最远路程,若无可行解,输出-1。
样例输入:
1
7 7
1 2 100
2 3 100
1 4 4
4 5 6
5 6 10
1 6 4
6 7 8
样例输出:
422
样例解释:起点,中转点和终点依次为:5 3 7或 7 3 5。
题目分析:dijkstra求最短路。
解题步骤:分别以1 到 n为起点用dijkstra算法求出1到n任意两点的最短路径,存到dis数组中,用dis[i][j]表示从点i到点j的最短路径,若两点无法到达用inf表示,将dis数组每行从小到大排序。然后枚举点1到点n为中转点时的最远路程,取最大值即可。
对于每个点i为中转点时的最远路径,就是它所能到达的点的最短路径的最大值和次大值之和。
例如:dis[i][1] 到 dis[i][n]排序后的结果是:0 2 4 5 inf inf,则i为中转点时的最远路程为 4 + 5 = 9。不选择inf,是因为i无法到达其对应的点。
AC代码:
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int N = 1010, inf = 1e9;
struct st{
int x, y;
bool operator < (const st &X) const{
return y > X.y;
}
};
int n, m, dis[N][N];
vector<st> v[N];
void dij(int u){
for(int i = 1;i <= n;i++) dis[u][i] = inf;
dis[u][u] = 0;
priority_queue<st> pq;
pq.push({u, dis[u][u]});
while(!pq.empty()){
int x = pq.top().x;
pq.pop();
for(int i = 0;i < v[x].size();i++){
int t = v[x][i].x;
if(dis[u][t] > dis[u][x] + v[x][i].y){
dis[u][t] = dis[u][x] + v[x][i].y;
pq.push({t, dis[u][t]});
}
}
}
}
void solve(){
scanf("%d %d", &n, &m);
for(int i = 1;i <= n;i++) v[i].clear();
while(m--){
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
v[x].push_back({y, z});
v[y].push_back({x, z});
}
for(int i = 1;i <= n;i++) dij(i);
for(int i = 1;i <= n;i++) sort(dis[i] + 1, dis[i] + 1 + n);
int ans = -1;
for(int i = 1;i <= n;i++){
int cnt = 0, res = 0;
for(int j = n;j >= 1;j--){
if(dis[i][j] != 0 && dis[i][j] < inf / 2){
res += dis[i][j];
cnt++;
if(cnt == 2) break;
}
}
if(cnt == 2) ans = max(ans, res);
}
if(ans == -1) printf("-1\n");
else printf("%d\n", ans);
}
int main(void){
int t;
scanf("%d", &t);
while(t--) solve();
return 0;
}
时间复杂度:O(nmlogn + n^2logn),nmlogn是执行了n次dijkstra算法,n^2logn是对dis数组进行排序。
空间复杂度:O(n ^ 2)。

浙公网安备 33010602011771号