分析题意可知,目的就是从起点出发,然后经过指定的五个节点(到达第五个节点就可以停止)。
因此我们要做的就是制定合理的方案先后经过这个五个节点,但是没有别的办法只能依次枚举所有情况,dfs暴搜,即5!种方案。
然后问题就转换成从起点开始,依次遍历五个节点的最短路问题。
但是发现这样做的时间复杂度太高了,求一次最短路是$mlog~n$,总共就是:$5!m{log~n}$,大概是$1.8e8$太大了。
于是想到可以先打表,求出从这六个节点的每一个节点出发,到达另五个节点的最短路径,然后再暴搜、查表这样就可以变成:$6m{log~n}+5!$,大概就是$9e6$。
C++ 代码
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int N = 50010 , M = 100010 , INF = 0x3f3f3f3f;
typedef pair<int , int> PII;
int e[2 * M] , ne[2 * M] , w[2 * M] , h[N] , idx;
int rel[6];
bool st[N];
int dist[6][N];
int n , m;
void add(int a , int b , int c)
{
e[idx] = b , ne[idx] = h[a] , w[idx] = c , h[a] = idx++;
}
void dijkstra(int start , int dist[])
{
memset(dist , 0x3f , N * 4);
dist[start] = 0;
memset(st , 0 , sizeof st);
priority_queue<PII , vector<PII> , greater<PII>> heap;
heap.push({0 , start});
while(heap.size())
{
auto t = heap.top();
heap.pop();
int ver = t.second , distance = t.first;
if(st[ver]) continue;
for(int i = h[ver] ; ~i ; i = ne[i])
{
int j = e[i];
if(dist[j] > dist[ver] + w[i])
{
dist[j] = dist[ver] + w[i];
heap.push({dist[j] , j});
}
}
}
}
int dfs(int u , int start , int distance)
{
if(u == 5) return distance;
int res = INF;
for(int i = 1 ; i <= 5 ; i++)
{
if(!st[i])
{
int next = rel[i];
st[i] = true;
res = min(res , dfs(u + 1 , i , distance + dist[start][next]));
st[i] = false;
}
}
return res;
}
int main()
{
cin >> n >> m;
rel[0] = 1;
for(int i = 1 ; i <= 5 ; i++) cin >> rel[i];
memset(h , -1 , sizeof h);
while(m--)
{
int a , b , c;
cin >> a >> b >> c;
add(a , b , c) , add(b , a , c);
}
for(int i = 0 ; i <= 5 ; i++)
dijkstra(rel[i] , dist[i]);
memset(st , 0 , sizeof st);
cout << dfs(0 , 0 , 0) << endl;
return 0;
}
tql