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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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