bellman ford不常用下面有它的优化spfa
for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { d[v[i]] = min(d[v[i]], d[u[i]] + w[i]); } }
dijkstra
d[s] = 0;//自己到自己0 for (int i = 0; i < n; i++) { int t = -1; for (int j = 0; j < n; j++) { if (!v[j]) { if (t == -1 || d[j] < d[t]) { t = j; } } } v[t] = 1; for (each edge e of t) { relax(e);//松弛 } }
floyd
for (int k = 0; k < n; k++) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { f[i][j] = min(f[i][j], f[i][k]+f[k][j]) } } }
spfa(洛谷大佬代码)
void spfa() { queue<int> q; //spfa用队列,这里用了stl的标准队列 for(int i=1; i<=n; i++) { dis[i]=inf; //带权图初始化 vis[i]=0; //记录点i是否在队列中,同dijkstra算法中的visited数组 } q.push(s); dis[s]=0; vis[s]=1; //第一个顶点入队,进行标记 while(!q.empty()) { int u=q.front(); //取出队首 q.pop(); vis[u]=0; //出队标记 for(int i=head[u]; i; i=edge[i].next) //邻接表遍历,不多解释了(也可用vector代替) { int v=edge[i].to; if(dis[v]>dis[u]+edge[i].dis) //如果有最短路就更改 { dis[v]=dis[u]+edge[i].dis; if(vis[v]==0) //未入队则入队 { vis[v]=1; //标记入队 q.push(v); } } } } }
例 : luogu p3371 预备知识: 链式前向星
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e4 + 5; const int maxm = 5e5 + 5; const ll inf = 2147483647; struct edge{ int next,to,w; }e[maxm]; int head[maxn], cnt, n, m, s, vis[maxn], dis[maxn];//head初始化为0 priority_queue<int, vector< pair<int, int> >, greater< pair<int, int> > >q;//最小堆,dijkstra找最短距离的 inline void add(int u, int v, int w){//链式向前星 e[cnt].w = w;//存权重 e[cnt].to = v; e[cnt].next = head[u]; head[u] = cnt++; } void dijkstra(){ q.push(make_pair(0, s));//起点s进去 while(!q.empty()){//空了就全搞好了 int now = q.top().second;//当前点 q.pop();//没用了弹出 if(!vis[now]){//要没标记 vis[now] = 1;//标记了 for(int i = head[now]; i; i = e[i].next){//把与now有联系的都循环,i = 0就没了,head初始化就是0 int v = e[i].to; if(dis[v] > dis[now] + e[i].w){ dis[v] = dis[now] + e[i].w; q.push(make_pair(dis[v], v));//发现它变小了就推进去 } } } } } int main(){ //ios_base::sync_with_stdio(0); //cin.tie(); cout.tie(); cin>>n>>m>>s; int x, y, z; for(int i = 1; i <= m; i++){ cin>>x>>y>>z; add(x, y, z);//链式向前星 } for(int i = 1; i <= n; i++) dis[i] = inf;//初始化 dis[s] = 0;//自己 dijkstra(); for(int i = 1; i <= n; i++){ cout<<dis[i]<<' '; } return 0; }
例 :luogu p1821 正反两次最短路(大佬代码)
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<vector> using namespace std; struct edge { int u,v; }; vector<edge> g[3][1001];//动态数组存边 queue<int> q;//队列(stl大法好) int n,m,f[3][1001],l,ans; bool vis[1001]; void spfa(int k)//k=1时正向图,k=2时反向图 { memset(vis,0,sizeof(vis));//初始化false vis[l]=true; f[k][l]=0; q.push(l); while(!q.empty()) { int news=q.front(); q.pop(); vis[news]=false; for(int i=0;i<g[k][news].size();i++) { int v=g[k][news][i].v,u=g[k][news][i].u; if(f[k][v]>f[k][news]+u) { f[k][v]=f[k][news]+u; if(!vis[v]) { vis[v]=true; q.push(v); } } } } } int main() { scanf("%d%d%d",&n,&m,&l); memset(f,0x3f3f3f,sizeof(f)); for(int a=1;a<=m;a++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); edge cmp; cmp.v=y; cmp.u=z; g[1][x].push_back(cmp);//正向建图 cmp.v=x; g[2][y].push_back(cmp);//反向建图 } spfa(1);//跑正向图 spfa(2);//跑反向图 for(int a=1;a<=n;a++) { if(a==l) { continue; } ans=max(f[1][a]+f[2][a],ans);//找最长的 } printf("%dn",ans); return 0; }
正向建就是求各点到终点最短路,反向建求终点到各点最短路
0 条评论