1.存入方式 :
a.稀疏图:邻接表:
int h[N], ne[M], w[M], e[M],idx;
void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
add(l, r, w), add(r, l, w);
b.稠密图:邻接矩阵
int g[N][N];
g[r][l] = g[l][r] = min(g[l][r],w); //min --if 有重边取最小即可
单源求最值
加法最小值
1.无负权边:dijkstra 理由:算法的前提是st数组里的都是已经确定是最短路的,若存在负权边会破坏这个前提。
2.有负权边:spfa
加法最大值
自我感觉spfa能求,还未验证过
乘法最小值
1.>=1:dijkstra 理由:算法的前提是st数组里的都是已经确定最小值的,若存在<1的话会破坏这个前提。
//算法合理性: (引用acwing 佬 Z_char 的评论)
Q:为什么spfa能求乘积最小和最大啊?
A:套用最短路和最长路就能求啊,所以SPFA当然可以求,SPFA的正确性是基于它的松弛操作,所以自然是可以求乘积最小值和乘积最大值的。
考虑Dij为什么不行,因为Dij的最短路算法是贪心的,它贪心的选最小的并且认为这个点不会被更新了,为什么不会被更新了?因为没有负权边,从而你加入优先队列里的dis只会越来越大,毕竟一个数+一个正数一定变大,不可能以后取出来某一个点更新这个点,故我这个点取出来了,就不会再使用。Dij的正确性是基于 “放入优先队列的点的dis是单调的” 这一条件。
所以 对于求最短路,我们要求dis单调递增,即不存在负权边,对于最大乘积,我们要求乘积只允许单调变小,即乘的在0,1之间,对于最小乘积,我们要求乘积必须单调变大,即所有边权都是>=1的
(似乎也不用严格单调,只要不增不减就行了)
//加上一点我的理解: 最短路 要求边只和单调递增(无负权边),so第一次遇到的就是最短路
//最大乘积 同理: 累积结果单调递减,第一次更新到的就是最大乘积
//最小乘积 同理: 累积结果单调递增,第一次更新到的就是最小乘积
练习题目:
1.1129. 热浪 - AcWing题库 --最简单的最短路径问题--单源最短路问题--直接建图
(单源最短路三种解法:AcWing 1129. 热浪 - AcWing)
//n--点数 m--边数
a.朴素dijkstra: O(n*n)
b.堆优化dijkstra:O(m*logn)
c.spfa: 一般:O(m) 最坏:O(n*m)
if(数据较小也可以用求解多源最短路的floyd写)
d.floyd --O(n*n*n) --优势简单,写得快,适用小范围多源 和单源
题意: 从一个点出发到 其余每一个点需要的最短路径
核心:对于每个点来说,第一次接收到的距离,就是最短路径
so思路:分别去起点到每一个点的最短路径,拿到所有路径中最大的路径maxl,
本质: 求时间最短问题,可以看成求所有最短路里面的最大值(定起点--单源最短路)
//多源最短路问题:但是数据范围较大,floyd 失败,可以使用堆优化 dijkstra +n次循环找最小
//本题涉及思想:
a.最短路中改个符号求最长路
b. 最短路中 + 换* (上面的Q就这题的一些解释)
标签: 有向图,边为1 ,一条线连续建图:
如图:建立这样的边权为1的C((n,2) 条边
6.903. 昂贵的聘礼 - AcWing题库903. 昂贵的聘礼 - AcWing题库903. 昂贵的聘礼 - AcWing题库(比较复杂的建图) -- 有限制的单源最短路建图
建图关键:1.建立一个虚拟起点:表示与原价(无优惠的价格),像下图:
数据:
建图:
代码:
2.条件的限制:建立等级区间,把在等级区间的节点路径进行更新,不在区间的不更新,如下图: