|
|
#include <bits/stdc++.h>
|
|
|
using namespace std;
|
|
|
|
|
|
typedef pair<int, int> PII;
|
|
|
|
|
|
const int N = 50010; // 车站数目
|
|
|
const int M = N << 1 << 1; // 公路数目,一般来说,N个节点,通常是2*N条边,如果是无向图,再乘2
|
|
|
const int INF = 0x3f3f3f3f;
|
|
|
|
|
|
int n, m; // 车站数目,公路数目
|
|
|
|
|
|
// 存图
|
|
|
int h[N], e[M], w[M], ne[M], idx;
|
|
|
void add(int a, int b, int c) {
|
|
|
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
|
|
|
}
|
|
|
|
|
|
int dis[6][N];
|
|
|
int id[6]; // 0号索引:佳佳的家,其它5个亲戚,分别下标为1~5,值为所在的车站编号
|
|
|
|
|
|
/*
|
|
|
1、用在Dijkstra中判断量不是出过队列,多次调用Dijkstra需要在函数体内进行状态重置
|
|
|
2、在dfs求全排列时,需要清空后记录在此路线上此 亲戚号 是不是走过了
|
|
|
*/
|
|
|
bool st[N];
|
|
|
|
|
|
/*
|
|
|
S:出发车站编号
|
|
|
dis[]:是全局变量dis[6][N]的某一个二维,其实是一个一维数组
|
|
|
C++的特点:如果数组做参数传递的话,将直接修改原地址的数据
|
|
|
此数组传值方式可以让我们深入理解C++的二维数组本质:就是多个一维数组,给数组头就可以顺序找到其它相关数据
|
|
|
计算的结果:获取到S出发到其它各个站点的最短距离,记录到dis[S][站点号]中
|
|
|
*/
|
|
|
void dijkstra(int S, int dis[]) {
|
|
|
dis[S] = 0;
|
|
|
memset(st, false, sizeof st);
|
|
|
priority_queue<PII, vector<PII>, greater<PII>> q;
|
|
|
q.push({0, S});
|
|
|
|
|
|
while (q.size()) {
|
|
|
auto t = q.top();
|
|
|
q.pop();
|
|
|
int u = t.second;
|
|
|
if (st[u]) continue;
|
|
|
st[u] = true;
|
|
|
for (int i = h[u]; ~i; i = ne[i]) {
|
|
|
int v = e[i];
|
|
|
if (dis[v] > dis[u] + w[i]) {
|
|
|
dis[v] = dis[u] + w[i];
|
|
|
q.push({dis[v], v});
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int ans = INF; // 预求最小先设最大
|
|
|
|
|
|
// u:第几个亲戚
|
|
|
// pre:前序站点
|
|
|
// sum:按此路径走的总距离和
|
|
|
void dfs(int u, int pre, int sum) {
|
|
|
if (u == 6) { // 如果安排完所有亲戚的拜访顺序,就是得到了一组解,尝试更新最小值
|
|
|
ans = min(ans, sum);
|
|
|
return;
|
|
|
}
|
|
|
for (int i = 1; i <= 5; i++) // 在当前位置上,枚举每个可能出现在亲戚站点
|
|
|
if (!st[i]) { // 如果这个亲戚没走过
|
|
|
st[i] = true; // 走它
|
|
|
// 本位置填充完,下一个位置,需要传递前序是i,走过的路径和是sum+dis[pre][id[i]].因为提前打好表了,所以肯定是最小值,直接用就行了
|
|
|
// 需要注意的是一维是 6的上限,也就是 佳佳家+五个亲戚 ,而不是 车站号(佳佳家+五个亲戚) !因为这样的话,数据就很大,数组开起来麻烦,可能会MLE
|
|
|
// 要注意学习使用小的数据标号进行事情描述的思想
|
|
|
dfs(u + 1, i, sum + dis[pre][id[i]]);
|
|
|
st[i] = false; // 回溯
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
scanf("%d %d", &n, &m); // 车站数目和公路数目
|
|
|
|
|
|
id[0] = 1; // 佳佳是0,id[0]=1,表示佳佳家在1号车站
|
|
|
for (int i = 1; i <= 5; i++) scanf("%d", &id[i]); // 五个亲戚所在车站编号,比如id[1]=2,描述1号亲戚在2号车站
|
|
|
|
|
|
// 建图完成后,图中的节点其实是 车站的站点编号,而不是亲戚编号
|
|
|
memset(h, -1, sizeof h); // 为了存图,需要初始化邻接表
|
|
|
|
|
|
while (m--) { // 建图
|
|
|
int a, b, c;
|
|
|
scanf("%d %d %d", &a, &b, &c); // a号车站到b号车站,需要走的时间是c
|
|
|
add(a, b, c), add(b, a, c); // 无向图,双向建边
|
|
|
}
|
|
|
|
|
|
// 计算从某个亲戚所在的车站出发,到达其它几个点的最短路径
|
|
|
// 因为这样会产生多组最短距离,需要一个二维的数组进行存储
|
|
|
memset(dis, 0x3f, sizeof dis);
|
|
|
for (int i = 0; i < 6; i++) dijkstra(id[i], dis[i]);
|
|
|
// 枚举每个亲戚所在的车站站点,多次Dijkstra,分别计算出以id[i]这个车站出发,到达其它点的最短距离,相当于打表
|
|
|
// 将结果距离保存到给定的二维数组dis的第二维中去,第一维是指从哪个车站点出发的意思
|
|
|
|
|
|
// dfs还要用这个st数组做其它用途,所以,需要再次的清空
|
|
|
memset(st, 0, sizeof st);
|
|
|
|
|
|
// 1:准备走第一家亲戚(具体是a,b,c,d,e哪一家随意都可以)
|
|
|
// 0:前序是佳佳自己家,他自己家的序号是0号
|
|
|
// 0:已经走过的最短距离和是0
|
|
|
dfs(1, 0, 0);
|
|
|
|
|
|
// 输出结果
|
|
|
printf("%d\n", ans);
|
|
|
return 0;
|
|
|
} |