AcWing 1135. 新年好
题目传送门
#include
using namespace std;
typedef pair PII;
const int N = 50010; //车站数目
const int M = 200010; //公路数目
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 dist[6][N]; //到每个亲戚家的最短距离
int source[6]; //亲戚家,0号索引:佳佳的家在车站1,他有五个亲戚
bool st[N]; // Dijkstra堆优化版本专用,是否在队列中
// start:出发点
// dist[]:是全局变量dist[6][N]的某一个二维,其实是一个一维数组
// C++的特点,如果数组做参数传递的话,将直接修改原地址的数据
void dijkstra(int start, int dist[]) {
dist[start] = 0;
memset(st, 0, sizeof st);
priority_queue, greater> q;
q.push({0, start});
while (q.size()) {
auto t = q.top();
q.pop();
int u = t.second;
if (!st[u]) {
st[u] = true;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (dist[j] > dist[u] + w[i]) {
dist[j] = dist[u] + w[i];
q.push({dist[j], j});
}
}
}
}
}
int ans = INF;
// step:走的步数
// pre:前序结点
// sum:按此路径走的总距离和
// 返回值:从佳佳家出发,走完所有亲戚家,枚举所有全排列组合中找到的最小距离和
void dfs(int step, int pre, int sum) {
//如果完成全排列,那么返回最短的距离和
if (step == 5 + 1) {
ans = min(ans, sum);
return;
}
//预求最小先设最大
//五个亲戚家
for (int i = 1; i <= 5; i++)
if (!st[i]) { //如果这个亲戚没走过
int u = source[i]; //根据第几个亲戚,找出这家亲戚的节点号
st[i] = true; //走他
dfs(step + 1, i, sum + dist[pre][u]);
st[i] = false; //回溯
}
}
int main() {
cin >> n >> m;
source[0] = 1; // 1号车站是佳佳家,索引是0
for (int i = 1; i <= 5; i++) cin >> source[i]; //五个亲戚家
memset(h, -1, sizeof h); //初始化链表头
// m条边
while (m--) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
//计算从任意一点出发,到达其它几个点的最短路径
//第一个参数是出发点,第二个参数是个二维数组,描述到其它任意一个点的距离
memset(dist, 0x3f, sizeof dist); //将二维数组全部实始化为INF
for (int i = 0; i < 6; i++) dijkstra(source[i], dist[i]);
// dfs还要用这个st数组做其它用途,所以,需要再次的清空
memset(st, 0, sizeof st);
// 1:准备走第一家亲戚,0:前序是佳佳自己家,0:已经走过的距离和是0
dfs(1, 0, 0);
printf("%d\n", ans);
return 0;
}