模型:
在无向图中
以某一个点作为起点
其它若干个点(比如有a个)作为终点
求从起点出发 遍历所有终点的最短路(不需返回起点)
当关键点比较少的时候(有a+1个)
用a+1轮Dijkstra跑出相关点的单源最短路
然后DFS枚举每一种到达的顺序取最值
#include<iostream>
#include<algorithm>
#include<cstring>
#include<array>
#include<queue>
using namespace std;
typedef pair<int, int>PII;
const int N = 5e4 + 10;//点的个数
const int M = N * 4;//要建双向边 范围乘以2
const int INF = 0x3f3f3f3f;
int h[N], e[M], w[M], ne[M], idx;
int ter[10];//记录5个终点
int dist[10][N];//起点离散化
bool vis[N];
int n, m;
int res = INF;
void add(int a, int b, int v)
{
e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx++;
}
//第一个参数:以谁作为单源点(起点)
//第二个参数:使用第几层的dist数组
//每一层dist保存一个单源最短路的结果
void dijkstra(int st, int* dist)
{
//每轮dijkstra使用一个堆
priority_queue<PII, vector<PII>, greater<PII>>heap;
//每轮dijkstra初始化记录访问的数组
memset(vis, 0, sizeof vis);
//只初始化某一层的dist为正无穷 一个整数四字节
memset(dist, 0x3f, sizeof 4 * N);
dist[st] = 0;
heap.push({ 0,st });
while (heap.size())
{
PII t = heap.top();
heap.pop();
int u = t.second;
if (vis[u])continue;
vis[u] = true;
for (int i = h[u];~i;i = ne[i])
{
int j = e[i];//j表示另一端点
int v = w[i];//v表示边的权重
if (dist[j] > dist[u] + v)
{
dist[j] = dist[u] + v;
heap.push({ dist[j],j });
}
}
}
}
//第一个参数:遍历到了多少个终点
//第二个参数:当前的位置(离散化后)
//第三个参数:本次路径的权值
void dfs(int u, int pos, int dis)
{
if (u == 5)
{
res = min(res, dis);
return;
}
//DFS5个终点
for (int i = 1;i <= 5;i++)
{
if (vis[ter[i]])continue;
vis[ter[i]] = true;
dfs(u + 1, i, dis + dist[pos][ter[i]]);
vis[ter[i]] = false;
}
}
int main()
{
cin >> n >> m;
ter[0] = 1;//布置起点
for (int i = 1;i <= 5;i++)cin >> ter[i];
//邻接表表头初始化
memset(h, -1, sizeof h);
while (m--)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c), add(b, a, c);//无向图建边
}
memset(dist, 0x3f, sizeof dist);
//给6个关键点求单元最短路
//ter[i]使用的是第i层的dist数组
for (int i = 0;i <= 5;i++)dijkstra(ter[i], dist[i]);
memset(vis, 0, sizeof vis);
dfs(0, 0, 0);
cout << res << endl;
return 0;
}