05贪心算法-Dijkstra算法
问题描述:
请设计一个算法,实现在一个有向图中,给出一个源点,计算该源点到其他所有顶点的单源最短路径。
算法描述:
Dijkstra算法的目的是寻找单源最短路径,其具有以下最优子结构性质:最短路径上的子路径也是两个顶点的最短路径,此性质可以用cut&paste反证(见笔记),因此,该算法满足贪心算法性质,局部最优解也是全局最优解,属于贪心算法的一种。基于此思想,若想找到源点s到v的最短路径,只需要找到s到u的最短路径+u到v的最短路径,u是s到v最短路径上的一个顶点。
变量定义:
s:源点
w[i][j]:i到j的最短路径
S[i]:i点是否加入最短路径集合,=1,加入;=0,未加入。
d[i]:源点到i点的距离
n:顶点个数
m:边个数
算法描述:
设G为包含图中所有顶点的集合,S为包含最短路径顶点的集合。源点s一定在S中(距离为0),算法的目的就是从g中找到到s点距离最短的顶点集合,并将它们加入S中。
源点到i 的最短路径 = d[v]+w[v][i];
笔记:(-from MIT算法导论课程)
Dijkstra算法代码:
//dijkstra算法
#include<stdio.h>
#include<stdlib.h>
int w[1000][1000];//i到j的最短路径
int S[1000],d[1000];//最短路径点集合,0:没有加入 1:加入;源点到i最短路径
int n,m;//n个点,m条边
void init(){
//所有点初值设置为∞
for(int i=0;i<1000;i++)
for(j=0;j<1000;j++)
w[i][j] = 65535;
//自己到自己的距离是0
for(int x=0;x<n;x++)
w[x][x] = 0;
}
void getg(){
int u,v,w;//u、v点,权值w
for(int t=1;t<=n;t++){
scanf("%d%d%d",&u,&v,&w);
if(w[u][v]>w){
w[u][v] = w;
w[v][u] = w;
}
}
}
void dijkstra(int s){
for(int y=0;y<1000;y++)
S[y] = 0;//初始没有最短路径顶点加入
//将源点s到所有顶点的距离放到d数组中
for (int t=1;t<n;t++)
d[t] = w[s][t];
S[s] = 1;//表不为空,因为存在源点到源点
//对所有点进行循环,其中包含两个循环,一个用来找源点到目标点最短路径,另一个用来更新源点到目标点的最短路径
for(int x=1;x<n;x++){
int min = 65535,temp=0;
for(int i=1;i<n;i++){
if(!S[i]&&d[i]<min){//点没有加入并且比上一个距离小
min = d[i];
temp = i;//临时存放最短路径点
}
S[tmep]=1;//最短路径点已经加入;
}
for(int i=1;i<=n;i++){
if(d[temp]+w[temp][i]<d[i])//只有当源点到最短路径点距离+最短路径到该点距离<源点到该点距离时,才对d数组进行更新
d[i] = d[temp]+w[temp][i];
}
}
}
}
int main(){
printf("请输入顶点个数和边的个数:\n");
scanf("%d%d",&n,&m);
init();
getg();
int s;
scanf("%d",&s);//源点
dijkstra(s);
return 0;
}
20201022更新:
该算法简述:每次都从原点出发,遍历所有没有加入最短路径的顶点,并找到权值最小的顶点,加入最短路径,然后更新改顶点到其他顶点距离,每次可以找到一个最短路径顶点。最后循环该过程n次,n为顶点个数。