对于图的存储:
稠密图(边多),邻接矩阵存储
稀疏图(边少),邻接表存储
常用最短路的算法:
dijkstra单源非负边权最短路o(n²+m)
bellman_ford(o(nm))、SPFA(o(nm))单源负边权最短路
floyd(o³)多源最短路
1.单向图求来回最短路
题意:求起点到各个点再回到起点的最短路(单向图)。
求起点到各个点的最小花费,单源最短路问题,再求各个点到起点的最小花费(因为是有向图,来回不一定连通),再求各个点到起点的最小花费时反向建图,再用一次单源最短路,最后累加和。
题意:n点m边有向图,求起点到各点,每次到达一个点须返回起点的最短路
先正向建图dijkstra求单源最短路,再反向建图求返回到起点的(逆向)单源最短路,加和即可
题意:n节点m条路,求每个节点到x节点来回的最短路中最长的那一条路
单源最短路问题,有向图,建俩图,dijkstra计算来回的最短路,枚举求最大值
2.求各个点到某一节点距离之和最短的点及距离和
题意:给出n个节点的树,问医院放在哪个节点使个节点到医院距离最小
folyd求出任意两点的距离,用额外的数组维护节点的人数,枚举每个节点更新最短距离
题意:求某点,满足到f个点的距离之和最小
每个点分别到这f个点的最小距离,直接用floyd计算,然后枚举每个点,算出距离总和,更新距离和最小的一个点记录下标并输出
floyd多源最短路,引用题解里的一句话“每次更改传送门后不断在重复做Floyd,每个点都要当作一次中转点m,效率低下。既然每一次变化只改变了k和l之间的距离,我们只需要分别将k和l作为中转点来做Floyd。”这样ne5减为ne4就可以过了。
3.存在两点多边的情况
[USACO2.4]回家 Bessie Come Home - 洛谷
题意:给出p个相连的牧场,求出牛到Z谷仓的最短路。(可能有多条路连共同点)
两点可能存在多条路,读入时更新为最短的路。
d[i][j]=min(d[i][j],w);
//若为无向图,则额外写一行
d[j][i]=d[i][j];
4.求最长路问题
题意:求奶牛在n个城市中赚钱最多的数量,每个城市有赚钱上限,p条不花钱的单向路,f条花钱的路
求最长路(最多的钱数)。一种方法是初始化距离数组为0,松弛操作改为更新最大值。另一种方法是每条边边权都取负,就转化成了负权边的最短路。
做题时注意到的其他细节
题意:a经若干人转账给b,转账时包含手续费,问a至少多少钱才能使b收到100元
dijkstra求最短路,松弛操作改为比较相乘,输出最短路即可(这里边权不是累加关系,而是累乘)
[USACO09OPEN]Hide and Seek S - 洛谷
题意:求无向图中最短路中的最长路,输出节点编号、距离、有几个距离都是最远的节点
单源最短路问题,dijkstra,首先遍历一遍找出最大最短路径的距离并记录编号,最后统计出这个最大最短路径的数量即可(用map<int, int>记录当前最短路径出现的次数)
题意:给出n点m条长为k的路,破坏ij两点间的路,求使ab连通最少需要修多长的路
未破坏的道路可以走且不需要修复,消耗为0,把损坏的边标记一下,把没被标记的边重设为0。Floyd即可
题意:给出n点m边无向图,求出给定两点的最短路,输出(可能有多条)最短路包含的编号
直接Floyd,条件判断if(d[v][j]+d[j][u]==d[v][u]),枚举输出
题意:无向图种求多对点的最短路
想用Floyd,n范围1e5直接劝退,从题解中学到可以用多次dijkstra也可以达到相同效果