|
|
#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;
|
|
|
}
|