图论 —— 最短路 —— Dijkstra 算法
【概述】
Dijkstra 算法是单源最短路径算法,即计算起点只有一个的情况到其他点的最短路径,其无法处理存在负边权的情况。
其时间复杂度是:O(E+VlogV)
【算法分析】
将点分为两类,一类是已确定最短路径的点,称为:白点,一类是未确定最短路径的点,称为:蓝点。
求一个点的最短路径,就是把这个点由蓝点变为白点,从起点到蓝点的最短路径上的中转点在这个时刻只能是白点。
Dijkstra 算法的思想,就是一开始将起点到终点的距离标记为 0,而后进行 n 次循环,每次找出一个到起点距离 dis[u] 最短的点 u ,将它从蓝点变为白点,随后枚举所有白点 Vi,如果以此白点为中转到达蓝点 Vi 的路径 dis[u]+w[u][vi] 更短的话,这将它作为 Vi 的更短路径(此时还不能确定是不是Vi的最短路径)。
以此类推,每找到一个白点,就尝试用它修改其他所有蓝点,中转点先于终点变成白点,故每一个终点一定能被它的最后一个中转点所修改,从而求得最短路径。
以下图为例
算法开始时,作为起点的 dis[1]=0,其他的点 dis[i]=0x3f3f3f3f
第一轮循环找到 dis[1] 最小,将 1 变为白点,对所有蓝点进行修改,使得:dis[2]=2,dis[3]=4,dis[4]=7
此时,dis[2]、dis[3]、dis[4] 被它的最后一个中转点 1 修改了最短路径。
第二轮循环找到 dis[2] 最小,将 2 变成白点,对所有蓝点进行修改,使得:dis[3]=3、dis[5]=4
此时,dis[3]、dis[5] 被它的最后一个中转点 2 修改了最短路径。
第三轮循环找到 dis[3] 最小,将 3 变成白点,对所有蓝点进行修改,使得:dis[4]=4。
此时,dis[4] 被它的最后一个中转点 3 修改了最短路径,但发现以 3 为中转不能修改 5,说明 3 不是 5 的最后一个中转点。
接下来两轮循环将 4、5 也变成白点。
N轮循环结束,所有点的最短路径均可求出。
【算法描述】
设起点为 s,dis[v] 表示从 s 到 v 的最短路径,pre[v] 为 v 的前驱结点,vis[v] 用于记录 v 是否被访问过。
1.初始化:
dis[v]=0x3f3f3f3f(v≠s),vis[v]=false,即:从始点到各点的值初始化为一极大值,所有点均标记为未访问
dis[s]=0,pre[s]=0,即:始点到始点的距离为 0,且其没有前驱结点
2.算法主体:
for(int i=1;i<=n;i++) {int min=INF;int u=0;for(int v=1;v<=n;v++) { //在没有被访问过的点中找一个顶点u,使得dis[u]是最小的if( vis[v]==false && dis[v]<min) {min=dis[v];u=v;}}if(u==0)break;vis[u]=true;//u标记为已确定的最短路径for(int v=1;j<=n;j++) { //枚举与u相连的每个未确定的最短路的顶点if(dis[u]+w[u][v]<dis[v]) {dis[j]=dis[u]+w[u][v]; //更新最短路径pre[v]=u;//记录前驱}}
}
3.算法结束:
dis[v] 即为 s 到 v 最短距离,pre[v] 即为 v 的前驱结点,用来输出路径。
【模版】
1.简化版
简化版不可处理重边图
int dis[N];//单源最短距离
int G[N][N];//G[i][j]表示i到j的有向边长
bool vis[N];//表示w[i]是否已经计算完
void dijkstra(int n,int s){for(int i=1;i<=n;i++){int x;//x标记当前最短w的点int min_dis=INF;//记录当前最小距离for(int y=1;y<=n;y++){if(!vis[y] && min_dis>=dis[y]){x=y;min_dis=dis[x];}}vis[x]=true;for(int y=1;y<=n;y++) dis[y]=min(dis[y],dis[x]+G[x][y]);}
}
int main(){memset(dis,INF,sizeof(dis));memset(vis,0,sizeof(vis));int n,m;scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int x,y,dis;scanf("%d%d%d",&x,&y,&dis);G[x][y] = G[y][x] = dis; //无向图添边一次,有向图添边两次}int start;scanf("%d",&start);dijkstra(n,start);for(int i=1;i<=n;i++)printf("%d\n",dis[i]);return 0;
}
2.标准版
标准版适用于稀疏图,可处理重边图
int n,m;
struct Edge{//边int from;//边的起点int to;//边的终点int dis;//边的长度Edge(int f,int t,int d){//构造函数from=f;to=t;dis=d;}
};struct HeapNode{//Dijkstra用到的优先队列的结点int dis;//点到起点距离int u;//点的序号HeapNode(int a,int b){dis=a;u=b;}bool operator < (const HeapNode &rhs) const {return dis > rhs.dis;}
};struct Dijkstra{int n,m;//点数、边数vector<Edge> edges;//边列表vector<int> G[N];//每个结点出发的边的编号bool vis[N];//是否走过int dis[N];//起点s到各点的距离int p[N];//从起点s到i的最短路中的最后一条边的编号void init(int n) {//初始化this->n = n;for(int i=0;i<n;i++) //清空邻接表G[i].clear();edges.clear();//清空边列表}void AddEdge(int from,int to,int diss) {//添加边,若为无向图,调用两次edges.push_back(Edge(from,to,diss));m=edges.size();//边的个数G[from].push_back(m-1);//添加至边列表}int dijkstra(int s) {//求s到所有点的距离memset(dis,INF,sizeof(dis));memset(vis,false,sizeof(vis));dis[s]=0;priority_queue<HeapNode> Q;//优先队列Q.push(HeapNode(0,s));while(!Q.empty()) {HeapNode x=Q.top();Q.pop();int u=x.u;if(vis[u])//若已被访问continue;vis[u]=true;//标记为已访问for(int i=0;i<G[u].size();i++) {//枚举所有与当前点相连的边Edge &e=edges[G[u][i]];if(dis[e.to] > dis[u]+e.dis) {//更新距离dis[e.to] = dis[u]+e.dis;p[e.to]=G[u][i];Q.push(HeapNode(dis[e.to],e.to));}}}return dis[n];//返回起点s到终点n最短距离}
}DJ;int main()
{while(scanf("%d%d",&n,&m)!=EOF&&(n+m)){DJ.init(n);//初始化for(int i=0;i<m;i++) {int x,y,dis;scanf("%d%d%d",&x,&y,&dis);//无向图添边两次DJ.AddEdge(x,y,dis);DJ.AddEdge(y,x,dis);}int start;scanf("%d",&start);DJ.dijkstra(start);//求start到各点的距离for(int i=0,j=0,s=++start;i<n;i++)//输出start到各点的距离printf("%d->%d: %d\n",s,++j,DJ.dis[i]);}return 0;
}
图论 —— 最短路 —— Dijkstra 算法相关推荐
- 图论-最短路Dijkstra算法详解超详 有图解
整体来看dij就是从起点开始扩散致整个图的过程,为什么说他稳定呢,是因为他每次迭代,都能得到至少一个结点的最短路.(不像SPFA,玄学复杂度) 但是他的缺点就是不能处理带负权值的边,和代码量稍稍复杂. ...
- 单源最短路 Dijkstra算法 和 SPFA算法
单源最短路 •从一个点出发,到达其他顶点的最短路径的长度. •基本操作:松弛 •d[u]+map[u, v]< d[v]这样的边(u,v)称为紧的(tense),可以对它进行松弛(relax): ...
- 2019中山纪念中学夏令营-Day14 图论初步【dijkstra算法求最短路】
Dijkstra是我学会的第一个最短路算法,为什么不先去学SPFA呢?因为我在luogu上翻到了一张比较神奇的图: 关于SPFA -它死了 以及网上还有各位大佬的经验告诉我:SPFA这玩意很容易被卡. ...
- 图论算法讲解--最短路--Dijkstra算法
一.绪论 要学习最短路算法我们首先应该知道什么是图以及什么是最短路. 图在离散数学中的定义为:图G=(V,E)是一个二元组(V,E)使得E⊆[V]的平方,所以E的元素是V的2-元子集.为了避免符号上的 ...
- 03 最短路 dijkstra算法spfa算法floyd算法(附带实例代码) 图论-1
文章目录 最短路 邻接表的图如下 邻接矩阵如下图 链表实现邻接表实现代码 单源最短路径 Dijkstra 算法 朴素版本 Dijkstra 实现代码 堆优化的dijkstra算法代码实现 Bellma ...
- 最短路dijkstra算法详解_图论系列开始填坑--Dijkstra,单源最短路
暑假只有最开始的几天最有意思,考完试玩了几天就感觉到了无聊.抱着想要出去走走的心态,我制定了一个出行路线图,我在1号城市,想去看一看2,3,4,5号城市(每去一个城市都从1号城市出发),一切准备就绪, ...
- 单源最短路——dijkstra算法
Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止. 问 ...
- 图论 —— 最短路 —— Bellman-Ford 算法与 SPFA
[概述] Bellman-Ford算法适用于计算单源最短路径,即:只能计算起点只有一个的情况. 其最大特点是可以处理存在负边权的情况,但无法处理存在负权回路的情况. 其时间复杂度为:O(V*E),其中 ...
- POJ-3268-最短路(dijkstra算法)
Silver Cow Party Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 12494 Accepted: 5568 ...
最新文章
- 技能树升级——Chrome Headless模式 - 全栈客栈 - SegmentFault
- jsp页面获取参数的方法(url解析、el表达式赋值、session取值)【原创】
- explain 之key || explain 之 rows || explain 之 extra
- hadoop-hbase-spark单机版安装
- 计算机等级考试真题演示,全国计算机等级考试二级真题测试(答案)四、演示文稿题-日...
- 51单片机之特殊功能寄存器SFR
- python群发邮件 不进垃圾箱_实战邮箱群发2000封邮件不进垃圾箱
- 2. Rust的三板斧 安全,迅速,并发
- GetFlashInfo V7.5_u盘芯片检测工具
- 解决qt.qpa.xcb: could not connect to display问题
- 单目3D多人姿态估计网络(整合自上而下和自下而上网络)
- 2021年危险化学品经营单位主要负责人考试及危险化学品经营单位主要负责人复审模拟考试
- 系统集成15真题解析
- 逆势增长背后的启示:亚信科技公布2022中期业绩
- iOS开发键盘设置,IOS7深灰色键盘
- cytoscape3.2.0 java_【看图说话】Cytoscape的“傻瓜式”教程
- 雅虎瓦片地图切片问题
- 创造与魔法台更新维护服务器,创造与魔法27日更新维护公告 数据互通交流不愁...
- 计算机国二考多久出来的,2008年国二(国家计算机二级考试)什么时候举行?...
- java 修改文件MD5值