单源最短路径 -- Dijkstra算法
2016-11-04 21:26
357 查看
求一个点(源点)到其余点的最短路径问题,利用f数组记录该节点的父节点,以便以后打印路经的时候,倒着回去的时候打印路径
(2)利用邻接表来实现Dijkstra算法,这是加入了邻接表,是算法的时间复杂度降低
建图的空间复杂度为O(m),遍历每一条边的时间复杂度为O(m)
#include<iostream>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#include<iomanip>
#define inf 0x3f3f3f3f
#define maxn 20
using namespace std;
struct node{
int to;
int w;
int next;
};
node edge[maxn];//存储边的信息数组
int book[maxn];//标记一下该条边是否已经确定是最小边了
int head[maxn];//存放i节点的第一条边在edge数组里面的位置
int dis[maxn];//存放num点到每个点的最短距离
int n,m,num;//num为要求的点,即该点到其他点的最短距离
int main()
{
scanf("%d%d%d",&n,&m,&num);
memset(head,-1,sizeof(head));//初始化为-1的是head数组
memset(dis, inf, sizeof(dis));
memset(book, 0,sizeof(book));
for(int i=0;i<m;i++)//邻接表的建立过程
{
int front;
scanf("%d%d%d",&front,&edge[i].to,&edge[i].w);
edge[i].next=head[front];
head[front]=i;
}
int k=head[num];//以num为节点,遍历与它相连的每一条边
dis[num]=0;//到本身的距离为0
book[num]=1;
while(k!=-1)//也算是对dis数组初始化的一部分
{
dis[edge[k].to]=edge[k].w;
k=edge[k].next;
}
for(int i=1;i<n;i++)//一共要计算n-1个点,因为剩下最后一个点后,该点的dis距离就是最短的
{
int Min=inf,t;
for(int j=1;j<=n;j++)//遍历dis数组里面的每一条边,找出离num点最近的点
{
if(book[j]==0 && Min>dis[j])
{
Min=dis[j];
t=j;
}
}
book[t]=1;
int l=head[t];
while(l!=-1)//遍历t点所连接的每一条边,看能否松弛
{
//edge[l].w代表第l条边的权值,dis[t]代表num点到t点的最短距离
//edge[l].to代表第l条边的终点,dis[edge[l].to]代表num点到edge[l].to的距离
if(!book[edge[l].to] && edge[l].w+dis[t]<dis[edge[l].to])
dis[edge[l].to]=edge[l].w+dis[t];
l=edge[l].next;//l边的下一条边,即与t点相连的下一条边
}
}
printf("\n");
for(int i=1;i<=n;i++)
{
printf("%d ",dis[i]);
}
printf("\n");
return 0;
}
/*
输入数据
6 9 1
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
输出结果
0 1 8 4 13 17
*/
(3)继续对上面的第二种算法进行优化,在判断离dis数组最近距离的点的时候利用堆排序,是该部分算法的时间复杂度由O(N)降低到O(logN)
#include<iostream> //没有利用邻接表存储图形结构的算法,该种方法存储图的空间复杂度为O(n*n),遍历每一条边的时间复杂度为O(m) #include<cstdio> //算法的时间复杂度为O(n*n) #include<cstdlib> #include<cstring> //有缺点,就是没法解决带有权值是负值的边 #include<string> #include<queue> #include<algorithm> #include<map> #include<iomanip> #include<stack> #define INF 99999999 #define MAX 20 using namespace std; int dis[MAX]; int city[MAX][MAX]; int book[MAX];//标记数组 ,为1代表该 dis[i]为确定的值,也就是真的最短路径,0代表不确定该路径是不是最短路径 int f[MAX];//用来存放该节点的父节点是谁 stack <int> a, b; int main() { int n,m,node; scanf("%d%d",&n,&m);//n点的个数,m边的条数 //建立城市之前的关系图,自身到自身距离为0,两个城市无法到达则为INF for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { if(i==j) city[i][j]=0; else city[i][j]=INF; } int x,y,r; //输入题目给出的两个城市之间的距离 for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&r); city[x][y]=r; } scanf("%d",&node);//输入要求的那个点,求该点到其他点的最短路径 //初始化dis数组,里面存放的是一开始,node点到其余各点的路径 for(int i=1;i<=n;i++) { dis[i]=city[node][i]; if(dis[i] < INF) f[i] = 1; } //初始化book数组,其实可以把数组定义main函数外面(即book数组是全局变量),book数组里面的每个元素都是0 memset(book,0,sizeof(book)); book[node]=1;//自己到本身的距离是0,确定的,所以一开始就把book[node]标记为确定值 //Dijkstra算法的核心语句 for(int t=1;t<n;t++)//一共需要计算多少次,因为当算到最后一个点的时候,没有其他选择了, { // 该点的dis[i]就是最短路径,确切值 int Min=INF,temp; for(int i=1;i<=n;i++) { if(book[i]==0 && dis[i]<Min) { Min=dis[i]; temp=i; } } book[temp]=1; for(int i=1;i<=n;i++) { if(!book[i] && city[temp][i]<INF) { if(dis[i]>dis[temp]+city[temp][i])//dis[i]代表从1号顶点到i号定点的起始最短路径,如果经过temp点一转后 dis[i]=dis[temp]+city[temp][i];//路径变短了,则更新这两点之前的最短路径(此时的最短路径 f[i] = temp; } // 不一定是最短的),已经被book标记的dis[i]才是最短路径,即book[i]=1 } } //打印出缩短后的路径,city[i][j]代表i点到j点的最短距离 for(int i=1;i<=n;i++) printf("%d ",dis[i]); printf("\n"); int i = f[6]; a.push(6); while(i != 1) { a.push(i); i = f[i]; } printf("从1点到6点的最短路径的走法:\n"); printf("1 "); while(!a.empty()) { printf("%d ",a.top()); a.pop(); } printf("\n"); return 0; } /*测试数据 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 1 程序运行效果 0 1 8 4 13 17 从1点到6点的最短路径的走法: 1 2 4 3 5 6 */
(2)利用邻接表来实现Dijkstra算法,这是加入了邻接表,是算法的时间复杂度降低
建图的空间复杂度为O(m),遍历每一条边的时间复杂度为O(m)
#include<iostream>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#include<iomanip>
#define inf 0x3f3f3f3f
#define maxn 20
using namespace std;
struct node{
int to;
int w;
int next;
};
node edge[maxn];//存储边的信息数组
int book[maxn];//标记一下该条边是否已经确定是最小边了
int head[maxn];//存放i节点的第一条边在edge数组里面的位置
int dis[maxn];//存放num点到每个点的最短距离
int n,m,num;//num为要求的点,即该点到其他点的最短距离
int main()
{
scanf("%d%d%d",&n,&m,&num);
memset(head,-1,sizeof(head));//初始化为-1的是head数组
memset(dis, inf, sizeof(dis));
memset(book, 0,sizeof(book));
for(int i=0;i<m;i++)//邻接表的建立过程
{
int front;
scanf("%d%d%d",&front,&edge[i].to,&edge[i].w);
edge[i].next=head[front];
head[front]=i;
}
int k=head[num];//以num为节点,遍历与它相连的每一条边
dis[num]=0;//到本身的距离为0
book[num]=1;
while(k!=-1)//也算是对dis数组初始化的一部分
{
dis[edge[k].to]=edge[k].w;
k=edge[k].next;
}
for(int i=1;i<n;i++)//一共要计算n-1个点,因为剩下最后一个点后,该点的dis距离就是最短的
{
int Min=inf,t;
for(int j=1;j<=n;j++)//遍历dis数组里面的每一条边,找出离num点最近的点
{
if(book[j]==0 && Min>dis[j])
{
Min=dis[j];
t=j;
}
}
book[t]=1;
int l=head[t];
while(l!=-1)//遍历t点所连接的每一条边,看能否松弛
{
//edge[l].w代表第l条边的权值,dis[t]代表num点到t点的最短距离
//edge[l].to代表第l条边的终点,dis[edge[l].to]代表num点到edge[l].to的距离
if(!book[edge[l].to] && edge[l].w+dis[t]<dis[edge[l].to])
dis[edge[l].to]=edge[l].w+dis[t];
l=edge[l].next;//l边的下一条边,即与t点相连的下一条边
}
}
printf("\n");
for(int i=1;i<=n;i++)
{
printf("%d ",dis[i]);
}
printf("\n");
return 0;
}
/*
输入数据
6 9 1
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
输出结果
0 1 8 4 13 17
*/
(3)继续对上面的第二种算法进行优化,在判断离dis数组最近距离的点的时候利用堆排序,是该部分算法的时间复杂度由O(N)降低到O(logN)
相关文章推荐
- 边上值非负的单源最短路径问题----Dijkstra算法
- Dijkstra算法--单源最短路径
- 用java编写的一个迪杰斯特拉算法(单源最短路径算法,Dijkstra算法)。
- 图论(四)------非负权有向图的单源最短路径问题,Dijkstra算法
- 单源最短路径问题(dijkstra算法 及其 优化算法(优先队列实现))
- Dijkstra算法(单源最短路径)
- 最短路径问题-----单源Dijkstra算法()
- 单源最短路径——Dijkstra算法,Bellman-Ford算法,SPFA算法
- 图算法 单源最短路径 Dijkstra算法(邻接表/邻接矩阵+优先队列STL)
- Dijkstra算法(注:单源最短路径的贪心算法)和数学归纳法<转>
- 每日一题 No.48 单源最短路径问题2(Dijkstra算法)
- DijKstra算法(单源最短路径)
- Dijkstra算法——单源最短路径问题
- 单源最短路径--Dijkstra算法
- 单源最短路径算法--Dijkstra算法和Bellman-Ford算法
- 求单源最短路径的Dijkstra算法分析与实现
- 图论——单源最短路径算法之Dijkstra算法
- Dijkstra算法(单源最短路径)
- 单源最短路径 dijkstra算法
- 单源最短路径-Dijkstra算法