1135. 新年好 (Dijkstra,dfs枚举)
重庆城里有 n 个车站,m 条 双向 公路连接其中的某些车站。
每两个车站最多用一条公路连接,从任何一个车站出发都可以经过一条或者多条公路到达其他车站,但不同的路径需要花费的时间可能不同。
在一条路径上花费的时间等于路径上所有公路需要的时间之和。
佳佳的家在车站 11,他有五个亲戚,分别住在车站 a,b,c,d,e
过年了,他需要从自己的家出发,拜访每个亲戚(顺序任意),给他们送去节日的祝福。
怎样走,才需要最少的时间?
输入格式
第一行:包含两个整数 n,m,分别表示车站数目和公路数目。
第二行:包含五个整数 a,b,c,d,e,分别表示五个亲戚所在车站编号。
以下 m 行,每行三个整数 x,y,t,表示公路连接的两个车站编号和时间。
输出格式
输出仅一行,包含一个整数 T,表示最少的总时间。
数据范围
1≤n≤50000
1≤m≤105
1<a,b,c,d,e≤n
1≤x,y≤n
1≤t≤100
输入样例:
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
解析:
这道题很容易想到用枚举的方式将所有的路线情况都枚举一遍,然后用最短路算法求出路线上两个点之间的最短距离,将路线上的所有距离相加即可得到最小距离,再从这些最小距离中选出最优解即可。但这里 5!中情况,如果直接按照上述说法进行处理则会超时,5!*o(mlogn)=x*1e7的时间,基本上会超时。
所以这里我们改变一下算法的顺序,我们先将 1,a,b,c,d,e,都先跑一遍最短路,然后再枚举路线,这样时间复杂度就变成了 5!+o(mlogn),这样就可以过了。
注意,这道题不能使用 spfa 算法,题目数据卡常数,所以使用 Dijkstra 算法跑最短路。
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>
#include<sstream>
#include<deque>
#include<unordered_map>
using namespace std;
typedef pair<double, int > PDI;
typedef pair<int, int> PII;
const int N = 5e4+5, M = 2e5 + 5;
int n, m;
int su[10];
int h[N], e[M], w[M], ne[M], idx;
int d[6][N], vis[N];
void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void Dijkstra(int start, int d[]) {
memset(vis, 0, sizeof vis);
d[start] = 0;
priority_queue<PII, vector<PII>, greater<PII>>q;
q.push({ d[start],start });
while (!q.empty()) {
int t = q.top().second;
q.pop();
if (vis[t])continue;
vis[t] = 1;
for (int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];
if (d[j] > d[t] + w[i]) {
d[j] = d[t] + w[i];
q.push({ d[j],j });
}
}
}
}
int dfs(int u,int num,int dist) {
if (num == 6) {
return dist;
}
int ret = 0x3f3f3f3f;
for (int i = 1; i <= 5; i++) {
if (vis[i] == 0) {
vis[i] = 1;
ret = min(ret, dfs(i, num + 1, dist + d[u][su[i]]));
vis[i] = 0;
}
}
return ret;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= 5;i++) {
scanf("%d", &su[i]);
}
su[0] = 1;
memset(h, -1, sizeof h);
for (int i = 1,a,b,c; i <= m; i++) {
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
add(b, a, c);
}
memset(d, 0x3f3f3f3f, sizeof d);
for (int i = 0; i <= 5; i++) {
Dijkstra(su[i], d[i]);
}
vis[0] = 1;
for (int i = 1; i <= 5; i++)vis[i] = 0;
cout << dfs(0, 1, 0) << endl;
return 0;
}