62 lines
2.0 KiB
C++
62 lines
2.0 KiB
C++
#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;
|
||
}
|