acwing-345. 牛站
考点
- Floyd
- 矩阵乘法
- 快速幂
- 线性DP
- 离散化
题解
见思路
思路
普通DP
代码一
设dp[i][j]
代表到达点j
恰好经过i
条边的最短路,显然有如下状态转移方程:
dp[i][j] = min(dp[i][j], dp[i - 1][k] + edge(k, j))
,其中k
点与j
点有连边。
第一份代码构思如下,显然会MLE,因为数组接近上亿。
1 |
|
代码二
第二份代码修改如下,使用滚动数组去掉第一维后,出现TLE,说明常数过大
1 |
|
代码三
常数优化在如下方面:
- 滚动数组本质是用两个数组交替保存结果,那么直接额外开
p
和q
两个数组,以减少上亿次&
运算的开销 - 上亿次的
min
操作常数开销也极大,部分情况min
的内部实现会变成递归;改用if
判断 - 去掉不必要的中间变量定义
得到AC代码:
1 |
|
代码四
根据代码三得知,实际上就是一个广义的Bellman-Ford算法。
所以不用耗时去建图,直接对全图所有边遍历n
次即可。
1 |
|
边为对象的Floyd
如果用邻接矩阵A
存边时,每次取:
1 | A[a[i]][b[i]] = min(A[a[i]][b[i]], c[i]); |
那么初始时的A[i][j]
显然代表i到j刚好经过1条边的最短路
假设我们去寻找一个i到j
的中间点k
,一定有:
\[
\forall i,j\in \left[ 1,m \right] , B\left[ i,j \right]
=\min_{1\leqslant k\leqslant m} \left\{ A\left[ i,k \right] +A\left[ k,j
\right] \right\}
\]
A[i][k]
代表点i
到点k
刚好经过1条边的最短路,A[k][j]
代表点k
到点j
刚好经过1条边的最短路,两个矩阵合并得到的新矩阵B
就代表i到j刚好经过2条边的最短路
,且该合并操作显然满足结合律,(AB)C
和A(BC)
显然没区别。
以此类推,1条边、2条边、4条边、8条边...显然可以采用快速幂的方式加速矩阵运算,将n
拆分成若干个2的幂次即可。
1 |
|