You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

62 lines
2.0 KiB

2 years ago
#include <bits/stdc++.h>
using namespace std;
const int N = 205;
unordered_map<int, int> id;
int s, e; // 起点 终点
int n, m; // 离散化后的节点号 m条边
int k; // 恰好k条边
int g[N][N]; // 图
int f[N][N]; // 最短距离
// 矩阵乘法
void mul(int a[][N], int b[][N]) {
int t[N][N];
memset(t, 0x3f, sizeof t);
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
t[i][j] = min(t[i][j], a[i][k] + b[k][j]);
memcpy(a, t, sizeof t);
}
// 快速幂
void qmi() {
// 使用拷贝矩阵后需要执行k-1次幂
// 解释拷贝过来原始距离数组g相当于计算出了两个点(i,j)之间经过一条边后的最短距离;
// 如果再乘一个矩阵g,表示又多经过了一条边也就是两条边此时发现其实最终是k-1次乘g
memcpy(f, g, sizeof f);
k--;
while (k) {
if (k & 1) mul(f, g); // 矩阵快速幂
mul(g, g);
k >>= 1;
}
}
int main() {
scanf("%d %d %d %d", &k, &m, &s, &e);
// 起点的离散化后号为1
id[s] = ++n;
// 如果e与s不同那么e的新号为2,否则为1
if (!id.count(e)) id[e] = ++n; // 注意这个起点与终点一样的坑
// 重新对s和e给定新的号码
s = id[s], e = id[e];
// 初始化邻接矩阵
memset(g, 0x3f, sizeof g);
while (m--) {
int a, b, c;
scanf("%d %d %d", &c, &a, &b);
if (!id.count(a)) id[a] = ++n; // 记录点的映射关系a-> id[a]
if (!id.count(b)) id[b] = ++n; // 记录点的映射关系b-> id[b]
a = id[a], b = id[b]; // 对a,b给定新的号码
// 利用新的号码将边长c记录到邻接矩阵中
g[a][b] = g[b][a] = min(g[a][b], c);
}
// 快速幂+动态规划思想
qmi();
// 输出从起点到终点恰好经过k条边的最短路径
printf("%d\n", f[s][e]);
return 0;
}