#include using namespace std; const int N = 205; unordered_map 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; }