新年好(堆优化版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)。

浙公网安备 33010602011771号