新年好(堆优化版dijkstra + dfs)

题目:新年好

题目链接:https://ac.nowcoder.com/acm/problem/50378

题意:给出一个强连通图(无重边),求从节点1开始,途径a, b, c, d, e五个点的最短路径。

输入描述:

第一行输入点数n(1 <= n <= 50000)和边数m(1 <= m <= 1e5)。

第二行输入a, b, c, d, e五个整数。(1 < a, b, c, d, e <= n)

接下来m行,每行三个整数x, y, t,表示x和y之间存在一条边权为t的无向边。(1 <= x, y <= n, 1 <= t <= 100)

输出描述:输出从1开始,经过a, b, c, d, e五个点的最短路径。

样例输入:

6 6

2 3 4 5 6

1 2 8

2 3 3

3 4 4

4 5 5

5 6 2

1 6 7

样例输出:

21

样例解释:

选择路径1 -> 6 -> 5 -> 4 -> 3 -> 2,边权分别为7, 2, 5, 4, 3,总和为21。

题目分析:堆优化版dijkstra + dfs。

解题步骤:以1, a, b, c, d, e为起点做6次堆优化版的dijkstra,然后用全排列枚举所有情况,取最小值即可。如1, a, b, c, d, e的值为 1到a的最短距离 + a到b的最短距离 + b到c的最短距离 + c到d的最短距离 + d到e的最短距离。

AC代码:

#include<iostream>

#include<vector>

#include<queue>

 

using namespace std;

const int N = 50010, M = 1e5 + 10, inf = 1e9;

struct st{

       int x, y;

       bool operator < (const st &X) const{

              return y > X.y;

       }

};

vector<st> v[N];

int dis[10][N], a[10], b[10], id[10], n, m, ans = 1e9;

 

void dij(int u){

       for(int i = 1;i <= n;i++) dis[u][i] = inf;

       dis[u][id[u]] = 0;

      

       priority_queue<st> pq;

       pq.push({id[u], dis[u][id[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 dfs(int x){

       if(x == 7){

              int res = 0;

              for(int i = 1;i <= 5;i++){

                     res += dis[a[i]][id[a[i + 1]]];

              }

              ans = min(ans, res);

             

              return;

       }

      

       for(int i = 2;i <= 6;i++){

              if(b[i] == 0){

                     b[i] = 1;

                     a[x] = i;

                     dfs(x + 1);

                     b[i] = 0;

              }

       }

}

 

void solve(){

       scanf("%d %d", &n, &m);

       id[1] = 1;

       for(int i = 2;i <= 6;i++) scanf("%d", &id[i]);

       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 <= 6;i++) dij(i);

   

       a[1] = 1;

       dfs(2);

       printf("%d\n", ans);

}

 

int main(void){

       solve();

      

       return 0;

}

时间复杂度:O(mlogm),全排列的时间复杂度可以忽略不计。

空间复杂度:O(n)。

posted @ 2021-10-29 17:01  思丶君  阅读(78)  评论(0)    收藏  举报