算法之最短路
Posted greed-vi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法之最短路相关的知识,希望对你有一定的参考价值。
最短路
我跟你讲SPFA已经死了好吧,SPFA+堆优又太难打,那就用dijkstra吧。(负权?我管它呢)
不加任何优化的裸dijkstra
一般般快吧,N^2,N=10000时可以卡过,很好打。
#include <bits/stdc++.h> #define MAXN 1005 using namespace std; long long LIS[MAXN][MAXN];//LIS数组存储图 long long dis[MAXN];//dis数组,存储最短长度值 long long vis[MAXN];//vis[i]代表这个点有没有被当做源点去搜索过,1为有,0为没有。这样就不会重复搜索了。 long long N,M,S; void dijkstra(long long x)//主函数,参数是源点编号 { long long start=x;//先从源点搜索 for(long long i=1;i<=N;i++) dis[i]=LIS[x][i];//先更新一遍 dis[start]=0; vis[start]=1;//标记源点已经搜索过 for(long long i=1;i<=N-1;i++) { long long MINN=2147483647;//比较 for(long long j=1;j<=N;j++) if(vis[j]==0&&MINN>dis[j]) MINN=dis[j],start=j;//找到离源点最近的点,然后把编号记录下来,用于搜索,可优化 vis[start]=1; for(long long j=1;j<=N;j++) dis[j]=min(dis[j],dis[start]+LIS[start][j]);//以新的点来更新dis。 } } int main() { cin>>N>>M>>S;//N是点数,M是边数,S是出发点 for (long long i=1;i<=N;i++)for (long long j=1;j<=N;j++)LIS[i][j]=2147483647; for (int i=1;i<=N;i++) LIS[i][i]=0; for(long long i=1;i<=M;i++) { long long a,b,c; cin>>a>>b>>c; LIS[a][b]=min(LIS[a][b],c);//判重 //LIS[b][a]=min(LIS[a][b],c);//这是双向边 } dijkstra(S);//以S为源点。 for(long long i=1;i<=N;i++) cout<<dis[i]<<" "; return 0; }
堆优化+前向星存储dijkstra
因为普通dijkstra需要找最小值然后更新,所以对于
for(long long j=1;j<=N;j++) if(vis[j]==0&&MINN>dis[j]) MINN=dis[j],start=j;
我们可以考虑用堆优化此过程,并且用链来存储,极大优化了内存
#include<bits/stdc++.h> #define MAXN 100010 #define MAXM 200010 using namespace std; long long last[MAXN],to[MAXM],nex[MAXM],v[MAXM],cnt=0,dis[MAXN]; bool vis[MAXN]; long long n,m,s; void add(int x,int y,int w) { nex[++cnt]=last[x];//上一条边的编号 to[cnt]=y;//此边到哪个点 v[cnt]=w;//权值 last[x]=cnt;//以x开头的最后一条边的编号 } priority_queue< pair<int,int> > q; void dijkstra(int s) { for(int i=1;i<=n;i++) dis[i]=2147483647;//其实这样也可以,因为会自己更新的 dis[s]=0; q.push(make_pair(0,s));//放入初始节点 while(!q.empty())//还未遍历完 { int x=q.top().second;//堆头节点,最小节点编号 q.pop();//用过弹出 if(vis[x]) continue;//已拓展的就不要再做了 vis[x]=1; for(int i=last[x];i;i=nex[i])//拓展 { int y=to[i];//下一个点 if(dis[y]>dis[x]+v[i]) { dis[y]=dis[x]+v[i]; q.push(make_pair(-dis[y],y));//用相反数实现小根堆,放入堆 } } } } int main() { cin>>n>>m>>s; for(int i=1;i<=m;i++) { int x,y,z; cin>>x>>y>>z; add(x,y,z);//单向边 } dijkstra(s); for (int i=1;i<=n;i++) cout<<dis[i]<<" "; return 0; }
以上是关于算法之最短路的主要内容,如果未能解决你的问题,请参考以下文章