最短路径———Dijkstra算法(南昌理工学院ACM集训队)


简介

最短路径:从图中的某个顶点出发到达另外一个顶点的所经过的边的权重和最小的一条路径,称为最短路径

算法:迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题(主要用于解决带权图中的单源最短路径)

迪杰斯特拉算法(Dijkstra)运用贪心思想,从起点开始,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到遍历到终点;

算法思想

由于算法运用贪心的思想,首先声明一个数组dis与一个数组visited分别用来保已经找到了最短路径的顶点和该点是否被访问过;

存储上采用邻接矩阵存图;
定义一个**二维数组map[MAX][MAX]**来表示一个图,数组的值是边权。

开始时,将源点x到各个点的距离存入dis数组中;即将map[x][j](j从1~n)存进dis(无法直接到达的点标为无穷大),并将visited数组中除x外所有值标为0,代表未访问;

随后,找到dis中最小权值的边的点min,此时min点已经确定,使visited[min]=1;

之后以min点为媒介,对未确定的点进行更新;

注意:对于已确定的点不参与最小值的查找和更新;
循环操作,直到所求的点被确定;

图解:
最短路径———Dijkstra算法(南昌理工学院ACM集训队)

算法详解

直接上代码(所求为源点到其余各个点的最短距离):

int map[110][110],dis[110],visited[110];//map存图,dis源点到各个点的距离,visited为标记数组

void Dijkstra(int n,int x)//n表示图中点的个数,x为源点
{
int i,p,j,min;
for (i=1;i<=n;i++)
{
dis[i]=map[1][i];//将最初源点所连接的点存入dis数组
visited[i]=0;//所有点计为0,即都未确定
}
visited[x]=1;//确定源点到自己的距离
for (i=1;i<=n;i++)
{
min=INF;
for (j=1;j<=n;j++)//找到dis中最小的未被确定的值
{
if(!visited[j] && dis[j]<min)
{
p=j;
min=dis[j];
}
}
visited[p]=1;//确定该最小值
for (j=1;j<=n;j++)//以刚才被确定的点为媒介,更新源点到其他未被确定的点的距离
{
if(!visited[j] && dis[p]+map[p][j]<dis[j])
{
dis[j]=dis[p]+map[p][j];
}
}
}

}

例题

之后老规矩(例题):
luoguP4779(单源最短路径(标准版))
最短路径———Dijkstra算法(南昌理工学院ACM集训队)

观察上面数据会发现,n最大可为10^5,此时,若是使用二维数组存储,则需要的数组空间会超出,
那么,我们要换用别的算法吗?
NO!
其他算法如由于其时间复杂度,被卡掉的几率很大;
所以仍然选择Dijkstra
这个时候就需要用到一个神奇的堆优化

Dijkstra堆优化

首先,存储方面,选择vector数组存储输入的路径,用小根堆加优先队列进行优化。

struct lq{
int x,d;
};
struct ha{//小根堆
int x,d;
bool operator <(const ha &a) const{//优先队列默认从大到小排列,这个让优先队列从小到大排列
return x>a.x;
}
};
priority_queue<ha> q;//优先队列
ha e;
lq t;
int dis[100005];//与普通版的dijkstra一样存储源点的最短路径
vector<lq> a[100005];//存储输入路径

输入:

int n,m,s,x,y,z;
cin>>n>>m>>s;
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);//考虑到m可能很大,用scanf读入可能好一点
t.d=y;
t.x=z;
a[x].push_back(t);//a数组的第i个元素到其结构体的d的距离是x;
//这里建议大家去详细看看其他博主对于vector数组的讲解;
}

主函数:

#define Max 0x3f3f3f3f;//在int 类型中,这个数相当于是正无穷
void Dijkstra(int n,int s){//n未结点个数,s是源点
for(int i=1;i<=n;i++)dis[i]=Max;//将dis数组都赋值未正无穷
e.d=s;
e.x=0;
dis[s]=0;
q.push(e);//将最开始的源点到源点加入优先队列
while(!q.empty()){//队列不为空则继续循环
e=q.top();q.pop();//出队操作
int v=e.d;
int u=e.x;
if(dis[v]<u) continue;//如果dis中的值比队列元素中的少,则后续操作无意义,直接下一位
int len=a[v].size();//数组元素的长度
for(int i = 0; i < len; i++)
{
lq g = a[v][i];
if (dis[v] + g.x < dis[g.d])//将所有比dis小的统统入队
{
dis[g.d] = dis[v] + g.x;
e.d = g.d;
e.x = dis[g.d];
q.push(e);
}
}
}
}

上述操作理解上较难,建议大家去看看其他有关vector数组和优先队列的文章;
o(*≧▽≦)ツ┏━┓

原创:https://www.panoramacn.com
源码网提供WordPress源码,帝国CMS源码discuz源码,微信小程序,小说源码,杰奇源码,thinkphp源码,ecshop模板源码,微擎模板源码,dede源码,织梦源码等。

专业搭建小说网站,小说程序,杰奇系列,微信小说系列,app系列小说

最短路径———Dijkstra算法(南昌理工学院ACM集训队)

免责声明,若由于商用引起版权纠纷,一切责任均由使用者承担。

您必须遵守我们的协议,如果您下载了该资源行为将被视为对《免责声明》全部内容的认可-> 联系客服 投诉资源
www.panoramacn.com资源全部来自互联网收集,仅供用于学习和交流,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。 敬请谅解! 侵权删帖/违法举报/投稿等事物联系邮箱:2640602276@qq.com
未经允许不得转载:书荒源码源码网每日更新网站源码模板! » 最短路径———Dijkstra算法(南昌理工学院ACM集训队)
关注我们小说电影免费看
关注我们,获取更多的全网素材资源,有趣有料!
120000+人已关注
分享到:
赞(0) 打赏

评论抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

您的打赏就是我分享的动力!

支付宝扫一扫打赏

微信扫一扫打赏