Dijkstra算法可用于:稠密图和顶点关系密切、指定一点到其余各个顶点的最短路径、不能处理含有负权边
题目描述
求图中1号顶点到2、3、4、5、6号顶点的最短路径
Input
6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
第一行:顶点数、边数
a b c:从a点到b点的权重为c
Dijkstra算法思路:类似于广搜一样,但不同的是需要使用优先队列,从1号顶点开始,将于它相邻的点入队,处理路径信息(该顶点路程等于前一个顶点路程加上边权),然后将到1号顶点路径最短的顶点出队,标记出队顶点,从出队顶点开始重复上述操作直到广搜结束
需要一个数组记录每个顶点到1号顶点的路程,如果需要输出路径时,那么还需要一个数组记录某个顶点的上一个顶点编号
代码里面采用了优先队列,因为每次都需要找到到1号顶点路径最短的顶点,最小优先队列的队首元素每次都是队内路径最短的顶点涉及到了结构体优先级的设置
代码如下
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <queue>
#define SIZE 101
using namespace std;
struct node
{
int x,s;
friend operator < (node a, node b)
{
return a.s > b.s;
}
}dis[SIZE];
int e[SIZE][SIZE],book[SIZE],n,m;
priority_queue<node >q;
//Dijkstra算法核心(类似于广度搜索的操作)
void Dijkstra()
{
node now;
now.x = 1;
now.s = 0;
dis[1].s = 0;
dis[1].x = -1;
q.push(now);
while(!q.empty())
{
//每次只标记出队元素
now = q.top();
book[now.x] = 1;
q.pop();
for(int i = 1;i <= n;i++)
{
node next;
next.x = i;
if(e[now.x][next.x] != INT_MAX && !book[next.x])
{
//如果next顶点到1号顶点的路程 > now顶点到1号顶点的路程+next->now的路程
if(dis[next.x].s > e[now.x][next.x] + dis[now.x].s)
dis[next.x].s = e[now.x][next.x] + dis[now.x].s;
//一定要记录该顶点到1号顶点的路径,在优先队列中需要判断
next.s = dis[next.x].s;
//记录该点的上一个点,用于路径输出
dis[next.x].x = now.x;
q.push(next);
}
}
}
}
//递归调用,路径输出
void Print(int x)
{
if(x == 1)
printf("1 ");
else
{
Print(dis[x].x);
printf("%d ",x);
}
}
int main()
{
int i,j,k,a,b,c;
scanf("%d %d",&n,&m);
//初始化
for(i = 1;i <= n;i++)
{
for(j = 1;j <= n;j++)
{
if(i == j)
e[i][j] = 0;
else
e[i][j] = INT_MAX;
}
}
//读入边
for(i = 0;i < m;i++)
{
scanf("%d %d %d",&a,&b,&c);
e[a][b] = c;
}
//初始化dis数组,这里是1号到其余各个顶点的初始路程
for(i = 1;i <= n;i++)
dis[i].s = e[1][i];
Dijkstra();
//1号顶点到其余顶点的最短路径
for(i = 1;i <= n;i++)
printf("%d ",dis[i].s);
//1号顶点到6号顶点的最短路径
printf("\n");
Print(6);
return 0;
}