旅行(堆优化版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)。

posted @ 2021-10-11 21:21  思丶君  阅读(54)  评论(0)    收藏  举报