最短路是很神奇的东西
//图上DP
都知道边有边权,可正可负
最短路算法的主体思想是通过对图的操作,使得两点间的最短路径被求出
多源最短路处理多个起点终点
单源最短路处理一个起点多个终点
floyd//多源最短路
spfa
spfa_slf(双端队列优化
dijkstra
dijkstra_heap(堆优化
//其实搜索也行2333//被打飞
0.无权图
无权图:各边权值相等的图// !=权值为0
@BFS 遍历全图,分层,ans = 层数*权值;
DFS不行 举个例子:
1.floyd
三重循环 k i j
基于DP思想,最外层k代表以k作为中转站的从i到j的最短路,即i->k->j;
依次循环更新
void floyd()
{
for(int k = 1; k <= n; k ++)
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++)
dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);
}
2.spfa /spfa_slf
依次枚举边 能更新就更新
特点是每个点经过次数不定
双端队列优化:每次选取更小边进行更新
spfa可以判负环
退出必须队列为空,不能中途退出
spfa:
queue < int > q;
void spfa(int s){
while(!q.empty()) q.pop();
memset(use,0,sizeof(use));
memset(dis,0x3f,sizeof(dis));
use[s] = true; dis[s] = 0;
q.push(s);
while(!q.empty()){
int u = q.front(); q.pop();
use[u] = false;
for(int i = first[u]; i != -1; i = nxt[i]){
int w = l[i].t;
if(dis[w] > dis[u] + l[i].v){
dis[w] = dis[u] + l[i].v;
if(use[w]) continue;
q.push(w); use[w] = true;
}
}
}
return;
}
spfa_slf
deque < int > q;
void spfa(int s){
while(!q.empty()) q.pop_front();
memset(use,0,sizeof(use));
memset(dis,0x3f,sizeof(dis));
use[s] = true; dis[s] = 0;
q.push_front(s);
while(!q.empty()){
int u = q.front(); q.pop_front();
use[u] = false;
for(int i = first[u]; i != -1; i = nxt[i]){
int w = l[i].t;
if(dis[w] > dis[u] + l[i].v){
dis[w] = dis[u] + l[i].v;
if(use[w]) continue;
if(q.empty() || dis[w] < dis[q.front()]) q.push_front(w);
else q.push_back(w);
}
}
}
return;
}
/*
有种特殊的优化叫做spfa_cy
学名:序号优化
如果当前点序号比队首序号小,就把它放在队首
不然就放队尾
玄学优化
*/
3.dij/dij_heap
每个点只入队一次,更新所有能更新的点
堆优化 每次优先更新更短的
可以中途退出
int dij(int s,int e)
{
memset(use,0,sizeof(use));
while(!q.empty()) q.pop();
q.push((re){s,0});
while(!q.empty())
{
re us = q.top();
q.pop();
int u = us.u;
if(u == e) return us.v;
if(use[u]) continue;
use[u] = true;
for(int i = first[u]; i != -1; i = next[i])
{
int w = l[i].t;
int rs = us.v + l[i].v;
q.push((re){w,rs});
}
}
return -1;
}