昨天的训练赛,就是上周六的cf,前三题没啥好说的,C题难点,难点主要在于怎么判断以及求出两个矩形的相交部分,当做一个小知识点记住吧。
这几天看了几道最短路的题目:首先总结一下知识点:
最短路的问题可以分为单源最短路问题 和 任意两点间的最短路径问题。
一、单源最短路问题:
1.dijkstra算法:
①算法思想:
是从起点开始,每次从还没扩展的点中选择距离起点最近(贪心)的点,并更新其所连接的点,直至所有的点均被扩展过(n-1个点即可)。
②普通算法时间复杂度:o(n^2),,,;
③缺点:
不能解决有负环的图(这里和为什么要每次选距离起点最近的点的原理是一样的,防止有另一条能通过已经被扩展过的点的更短的路径出现却已经不能再被更新),当然如果权值全为负值的话可以求最长路。
④二叉堆优化:(时间复杂度o( mlogN ) ):
就是用优先队列来实现每次选最近点的过程(一个点可能同时有多个出现在队列中,最短的那条肯定在队头,把它扩展完后该点就被标记了,所以其他该点直接continue跳过)。
2.Bellman-Ford(时间复杂度0(n*m)):显然这种算法可以处理负权问题
①原理:dist【y】>dist【x】+z,更新y点,直至图中不再出现该不等式。
②堆优化queue(SPFA):,,,
③队列实现弊端:在稠密图上不好使,o(n*m)。
3.有向无环图DAG 拓扑序遍历所有节点一次且仅一次( 时间复杂度o(n+m) ):
比如这道题目:BZOJ2200 道路与航线
题意:
给一张图,有有向边也有无向边,有向边均为负权值,无向边为正权,给定一起点,问从起点到达其他点的最短路长度。
分析:
二叉堆优化后的dijkstra算法时间快,但dijkstra不能处理负权值,spfa的可以处理负权但是这本题中会出现o(m*n)的时间复杂度,会TLE。但因为题目给出负权的边不会形成回路,所以先不考虑负权的边,先将图划分为多个联通块,然后联通块内部用dijkstra,外部宏观上按照拓扑序依次更新各个联通块。
那么怎么根据拓扑序求最短路呢?考虑前面的dijkstra算法的核心就是规定了一个遍历图中所有节点一次且仅一次的顺序,(相比之下spfa算法就显的比较暴力了,扩展后的点还有再扩展的可能),而规定这个顺序的目的是为了保证当前扩展的点为经过该点的路径的全局最优解,即不会再被后面的点所影响。而在拓扑序中,因为是按照点之间的可达关系排列点之间的顺序,所以一定能保证在之后的更新中也不会再次更新到该点,即可以保证扩展后的点不会在受后面点扩展的影响了。所以用拓扑排序来处理整个图的框架(遍历一遍拓扑序列即可),而对于被缩点的联通块们内部,用dijkstra。(怎么求拓扑序:思想就是选择入度为零的节点,然后删除该点,再找入度为零的节点,如果同时出现对个入度为零的点怎么办?随便规定个顺序就行了,因为该图一定是有向无环图,先处理谁都一样)。
The end;