#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#define inf 65535 //定义无穷大
using namespace std;
void Dijkstra(int n,int v,int dist[],int pre[],int c[][6]) //n为顶点个数,v代表源点,dist[i]记录每轮下来源点到第i个顶点的最短路径,pre[i]代表到第i个顶点的最短路径中i的上一个顶点的号码,c[][]为邻接矩阵
{
int s[6]; //s[]为记录每个顶点是否纳入S集合,1代表纳入,0代表不纳入,即s[i]属于V-S
for(int i=1;i<=n;i++)//初始化,先让每个节点的s[]都为0,dist[]为与顶点v直接相连的长度,如果没有就为无穷大
{
dist[i]=c[v][i];
s[i]=0;
pre[i]=dist[i]!=inf?v:inf;//如果dist[]存在说明顶点i与v有直接通路,那么i的上一个顶点就是v,否则就是无穷大
}
s[v]=1;//源点v肯定是要第一个送到集合S里面的
for(int i=1;i<=n-1;i++)//开始迭代,因为有n个顶点,因此一共需要迭代n-1轮
{
int min=inf,minv;//min和minv用于记录每轮dist[]的最小值和最小值对应的那个顶点号
for(int j=1;j<=n;j++)//一层循环搞定,就是擂台赛,注意一定要在不属于S的集合里面去寻找!所以要!s[j]
if(!s[j]&&dist[j]<min)
{
min=dist[j];
minv=j;
}
s[minv]=1;//找到之后把那个最小值对应的顶点纳入S集合
for(int j=1;j<=n;j++)//纳入集合之后需要修改剩余各个顶点(即不属于S集合)的 dist[]值,因为还有可能存在更短的路径!
if(!s[j]&&dist[minv]+c[minv][j]<dist[j])//如果真的存在的话
{
dist[j]=dist[minv]+c[minv][j];//修改dist[]值
pre[j]=minv;//同时也要更新它的上一个顶点,变成minv了
}
}
}
void print(int pre[],int v,int n,int dist[])//知道pre[]了,我想输入最终结果咋办呢?用这个函数实现
{
int s[20],top;//定义一个栈,因为最后的输出需要不断的弹栈,所以要建立这样的数据结构
for(int j=1;j<=n;j++)//针对顶点1到顶点n
{
int i=j;//因为后面j的值需要变化, 因此让i=j以避免影响for循环!
if(pre[i]==inf)//pre[i]=inf说明不通
continue;
else //如果通的话,先压栈,再弹栈
{
top=0;//初始化栈
do//只要最后的i不为源点序号v,说明它的前面一定还有顶点,就不断的压栈,
{
s[top++]=i;//压栈操作
i=pre[i];//同时i的值也随之改变
}while(i!=v);
cout<<v<<"-->";//下面是输出结果 ,一开始是从v开始
while(top!=0)//只要栈不空,就弹栈
{
cout<<s[--top];//弹栈操作
if(top!=0)//这里是个小技巧,如果当前顶点不是最后一个顶点,即栈不空,就要输出“-->”这个符号 ,最后一个顶点的后面当然啥符号也没有
cout<<"-->";
}
cout<<" 距离为"<<dist[j]<<endl;//同时输出最短路径的距离,注意这里输出的是dist[j],不是 dist[i],因为i的值早就发生了变化!
}
}
}
int main()
{
int c[6][6]={{inf,inf,inf,inf,inf,inf},//我的顶点是从1~5的,因此从0开始的就用inf代替,不影响最后结果
{inf,inf,10,inf,30,100},
{inf,inf,inf,50,inf,inf},
{inf,inf,inf,inf,inf,10},
{inf,inf,inf,20,inf,60},
{inf,inf,inf,inf,inf,inf}
};
int pre[6],dist[6],n=5;
Dijkstra(n,1,dist,pre,c);
print(pre,1,n,dist);
}
迪杰斯特拉算法
最新推荐文章于 2024-07-10 14:40:45 发布