-
题目大意:给定起点和终点,求经过k条边的最短路
-
思路:倍增Floyd 矩阵快速幂优化
其实,虽然被称作倍增Floyd,但和Floyd关系好像并不大?按dp思想理解,设f(k,i,j)表示经过k条边从i到j的最小花费,则
(f(k,i,j)=min(f(k-1,i,p)+f(1,p,j)))
k次Floyd显然会超时,现考虑定义新运算如下:
对一张有n个点的图,用n*n的邻接矩阵来存储,其中(i,j)表示从i到j的最短路长度
A矩阵表示经过x条边以后的最短路,B矩阵表示经过y条边以后的最短路
定义新运算:(A*B=C)
(C[i,j]=min_{k=1}^nA[i,k]+B[k,j])
对这种矩阵运算,满足结合律,可以用类似快速幂的倍增思想进行优化
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=210;//注意空间限制 数组开大直接报错
int s,e,k,n,m,book[3005];
struct data {//离散化用
int from,to,dis;
} node[3005];
struct Matrix {
int mp[maxn][maxn];
inline Matrix () {memset(mp,0x3f,sizeof(mp));}
Matrix operator *(const Matrix &a)const {
Matrix c;
for(int k=1; k<=n; ++k)
for(int i=1; i<=n; ++i)
for(int j=1; j<=n; ++j)
c.mp[i][j]=min(c.mp[i][j],mp[i][k]+a.mp[k][j]);
return c;
}
} f,ans;
void ksm(){
ans=f;
while(k) {
if(k&1) ans=ans*f;
f=f*f;
k>>=1;
}
}
int main() {
scanf("%d%d%d%d",&k,&m,&s,&e);
for(int i=1,x,y,z; i<=m; ++i) {
scanf("%d%d%d",&z,&x,&y);
book[++n]=x;
book[++n]=y;
node[i].from=x;
node[i].to=y;
node[i].dis=z;
}
sort(book+1,book+1+n);
int tot=unique(book+1,book+1+n)-(book+1);
for(int i=1; i<=m; ++i) {
node[i].from=lower_bound(book+1,book+1+tot,node[i].from)-book;
node[i].to=lower_bound(book+1,book+1+tot,node[i].to)-book;
f.mp[node[i].from][node[i].to]=f.mp[node[i].to][node[i].from]=node[i].dis;
}
s=lower_bound(book+1,book+1+tot,s)-book;
e=lower_bound(book+1,book+1+tot,e)-book;
n=tot;
//以上为离散化内容
--k;//经过k条边 需要进行k-1次floyd
ksm();
printf("%d",ans.mp[s][e]);
return 0;
}