K点最短路
在OI中,有一类经典的问题叫做经过K点的最短路径, 解题的思路大致是利用flyod和之前我们学习过的广义矩阵乘法, 矩阵快速幂
1. 分析
对于K点的最短路, 我们可以当作是一个传递闭包进行处理,k一定是可以被分解为是2的 ki 次方的相加, 如果一个传递闭包的级数为k,另外一个的级数为p,那么将这两个相称得到的就是进行k+p次的闭包
我们可以将最短路同理为闭包, K级就意味着在k个点上的最短路径, k+p则是他们和的点数的最短路径, 对于这个闭包运算的实现, 我们可以使用广义矩阵乘法
2 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include <iostream> #define N 520 using namespace std; int dp[N][N], vis[1001000]; int n,t,s,e,cnt; struct matrix { int dis[N][N]; matrix operator*(const matrix&x) const { matrix c; memset(c.dis,0x3f,sizeof c.dis); for (int k = 1; k <= cnt; k++) for (int i = 1; i <= cnt; i++) for (int j = 1; j <= cnt; j++) c.dis[i][j] = min(c.dis[i][j], dis[i][k] + x.dis[k][j]); return c; } }now,ans; int main() { memset(now.dis,0x3f,sizeof(now.dis)); scanf("%d%d%d%d",&n,&t,&s,&e); for (int i = 1;i <= t;i++) { int x,y,d; scanf("%d%d%d",&d,&x,&y); if(!vis[x]) {vis[x] = ++cnt;} if(!vis[y]) {vis[y] = ++cnt;} now.dis[vis[x]][vis[y]] = now.dis[vis[y]][vis[x]] = d; } n--; ans = now; while (n) { if(n&1) ans = ans*now; now = now*now; n >>= 1; } printf("%d\n",ans.dis[vis[s]][vis[e]]); }
|