https://www.luogu.com.cn/problem/P2886
看一眼本题,Floyd算法。那么什么是Floyd算法呢??
Floyd
Floyd是一种最短路算法,适用于点数较少的图
Floyd的本质是动态规划,它的状态定义以及转移:
设f[i][j]f[i][j]为ii到jj的最短距离
f[i][j]=min(f[i][j],f[i][k]+f[k][j])f[i][j]=min(f[i][j],f[i][k]+f[k][j])
代码实现:
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
下面让我们魔改一下
令f[k,i,j]表示 从i经过k条边到达j 原Floyd表达 从i 到j走1~k个点,最短路径是多少。
魔改后 转移方程 f[a+b,i,j]=min(f[a,i,k],f[b,i,k]),k=1~n。
d[a,i,k] 中的 k不是什么第 k 条边,而是表示从 i 走了 a 条边(就是相当于走了a步)以后到达的结点 k ,因此这个 k 是在 1 ~ N 之间的一个点。
这个转移方程表示从 i 到 j 走 a+b (x)条边,等于在所有从 i 走 a 条边到 k ,再从 k 走 b (x−a) 条边到 j 中取最小值。
这样我们要求的是经过 N 条边的最短路,最开始输入的每一个都是1条边(经过一条边的两个点的距离),那么我们要得到经过N条边就可以按照上述的方程,加 N-1 次 (d[2,i,j] = d[1,i,k] + d[1,k,j])
同时,这里可以用快速幂来优化。
这里有一百条边,用两百个点,给到1000.所以要离散化一下。
离散化
即在不i改变数据相对大小的前提下,对数据进行相应的缩小。通常使用STL算法离散化操作。
步骤为:排序,去重,lower bount。
代码如下:
sort(sub_a,sub_a+n);
int size=unique(sub_a,sub_a+n)-sub_a;//size为离散化后元素个数
for(i=0;i<n;i++) a[i]=lower_bound(sub_a,sub_a+size,a[i])-sub_a + 1;//k为b[i]经离散化后对应的值
本题代码如下
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<map> #define x first #define y second using namespace std; typedef pair<int,int> PII; const int N = 507; int k,n,m,S,E; int g[N][N]; int d[N][N]; void mul(int c[][N],int a[][N],int b[][N]){ static int temp[N][N]; memset(temp,0x3f,sizeof temp); for(int k = 1;k <= n;++k) for(int i = 1;i <= n;++i) for(int j = 1;j <= n;++j) temp[i][j] = min(temp[i][j],a[i][k] + b[k][j]); memcpy(c,temp,sizeof temp); } void qpow(){ memset(d,0x3f,sizeof d); for(int i = 1;i <= n;++i) d[i][i] = 0; while(k){ if(k & 1)mul(d, d, g);//d = d * g; mul(g, g, g);//g = g * g; k >>= 1; } } int main(){ cin>>k>>m>>S>>E; memset(g,0x3f,sizeof g); //这里g[i][i]不能置为0,因为这里g[i][j]表示的是从i走1条边到达j,i不能经过1条边到i,因此应该也是INF map<int,int>ids; while(m--){ int a,b,c; scanf("%d%d%d",&c,&a,&b); if(!ids.count(a))ids[a] = ++n; if(!ids.count(b))ids[b] = ++n; a = ids[a],b = ids[b]; g[a][b] = g[b][a] = min(g[a][b],c); } if(!ids[S])ids[S] = ++n; if(!ids[E])ids[E] = ++n; S = ids[S],E = ids[E]; qpow(); cout<<d[S][E]<<endl; return 0; }