本文紧接着上一篇文章,介绍图的两种最短路径算法----迪杰斯特拉算法和弗洛伊德算法。
Dijkstra
迪杰斯特拉是求单源最短路径的一种算法。它运用的是贪心的思想。
#include<stdio.h>
typedef int EdgeType;
typedef char VertexType;
#define MAXVEX 100
#define INFINITY 65535
typedef struct
{
VertexType vexs[MAXVEX];
EdgeType arc[MAXVEX][MAXVEX];
int numVertexs, numEdges;
}MGraph;
void CreateMGraph(MGraph *G)
{
int row = 0, column = 0, value = 0;
printf("请输入顶点数和边数\n");
scanf("%d %d",&G->numVertexs, &G->numEdges);
getchar();
printf("请输入顶点\n");
for (int i = 0; i < G->numVertexs; ++i)
{
scanf("%c",&G->vexs[i]);
getchar();
}
for (int i = 0; i < G->numVertexs; ++i)
{
for (int j = 0; j < G->numVertexs; ++j)
{
G->arc[i][j] = INFINITY;
}
}
printf("请输入边\n");
for (int i = 0; i < G->numEdges; ++i)
{
scanf("%d %d %d",&row, &column, &value);
G->arc[row][column] = value;
G->arc[column][row] = value; //无向图,若是有向图可以不添加
}
}
void show(MGraph *g)
{
for (int i = 0; i < g->numVertexs; ++i)
{
for (int j = 0; j < g->numVertexs; ++j)
{
printf("%7d",g->arc[i][j]);
}
printf("\n");
}
}
void shortestPath_Dijkstra(MGraph *g, int v)
{
int len = g->numVertexs;
int dis[len];
int visited[len];
int pre[len];
int min, k;
for (int i = 0; i < len; ++i)
{
dis[i] = g->arc[v][i];
visited[i] = 0;
pre[i] = 0;
}
dis[0] = 0;
visited[0] = 1;
for (int m = 1; m < len; ++m)
{
min = INFINITY;
for (int j = 0; j < len; ++j)
{
if (!visited[j] && min > dis[j])
{
min = dis[j];
k = j;
}
}
visited[k] = 1;
for (int i = 0; i < len; ++i)
{
if (!visited[i] && dis[i] > (min + g->arc[k][i]))
{
dis[i] = (min + g->arc[k][i]);
pre[i] = k;
}
}
}
for (int i = 0; i < len; ++i)
{
printf("%d\t",dis[i]);
}
}
int main()
{
freopen("5.txt","r",stdin);
MGraph *g = (MGraph*)malloc(sizeof(MGraph));
CreateMGraph(g);
shortestPath_Dijkstra(g,0);
//show(g);
return 0;
}
一共可以分为三个步骤
第一步,初始化,dis数组,初始化为所求点到各点的距离,dis[0]要赋为0,表示自己到自己的最短路径为0。visited数组赋为0,表示都没有找到最短路径,visited[0]赋为1.pre表示最短路径的此顶点的前一顶点。
第二步,找到距离起点最近的点k,并记录最小值。
第三步,第二步的最小值就是起点到k的最短路径,然后更新dis,看是否通过k点,比直接从起点走要近,如果近的话就进行更新,并且记录pre数组
循环二、三步。
5.txt:
9 14
A B C D E F G H I
0 1 10
0 5 11
1 2 18
1 6 16
1 8 12
2 3 22
2 8 8
3 4 20
3 7 16
3 8 21
4 5 26
4 7 7
5 6 17
6 7 19
Floyd
这是求多源最短路径的算法。当然也可以使用Dijkstra算法来对每个点求最短路径,能达到一样的效果,不过就不如Floyd算法简洁了。弗洛伊德是基于动态规划的思想。
#include<stdio.h>
typedef int EdgeType;
typedef char VertexType;
#define MAXVEX 100
#define INFINITY 65535
typedef struct
{
VertexType vexs[MAXVEX];
EdgeType arc[MAXVEX][MAXVEX];
int numVertexs, numEdges;
}MGraph;
void CreateMGraph(MGraph *G)
{
int row = 0, column = 0, value = 0;
printf("请输入顶点数和边数\n");
scanf("%d %d",&G->numVertexs, &G->numEdges);
getchar();
printf("请输入顶点\n");
for (int i = 0; i < G->numVertexs; ++i)
{
scanf("%c",&G->vexs[i]);
getchar();
}
for (int i = 0; i < G->numVertexs; ++i)
{
for (int j = 0; j < G->numVertexs; ++j)
{
G->arc[i][j] = INFINITY;
}
}
printf("请输入边\n");
for (int i = 0; i < G->numEdges; ++i)
{
scanf("%d %d %d",&row, &column, &value);
G->arc[row][column] = value;
G->arc[column][row] = value; //无向图,若是有向图可以不添加
}
}
void show(MGraph *g)
{
for (int i = 0; i < g->numVertexs; ++i)
{
for (int j = 0; j < g->numVertexs; ++j)
{
printf("%7d",g->arc[i][j]);
}
printf("\n");
}
}
void shortestPath_Floyd(MGraph *g)
{
int len = g->numVertexs;
int dis[len][len];
int pre[len][len];
for (int i = 0; i < len; ++i)
{
for (int j = 0; j < len; ++j)
{
pre[i][j] = j;
if (i == j) {
dis[i][j] = 0;
}
else
{
dis[i][j] = g->arc[i][j];
}
}
}
for (int k = 0; k < len; ++k)
{
for (int i = 0; i < len; ++i)
{
for (int j = 0; j < len; ++j)
{
if (dis[i][j] > (dis[i][k] + dis[k][j]))
{
dis[i][j] = dis[i][k] + dis[k][j];
pre[i][j] = pre[i][k];
}
}
}
}
for (int i = 0; i < len; ++i)
{
for (int j = 0; j < len; ++j)
{
printf("%d\t", dis[i][j]);
}
printf("\n");
}
printf("\n\n");
for (int i = 0; i < len; ++i)
{
for (int j = 0; j < len; ++j)
{
printf("%d\t", pre[i][j]);
}
printf("\n");
}
}
int main()
{
freopen("5.txt","r",stdin);
MGraph *g = (MGraph*)malloc(sizeof(MGraph));
CreateMGraph(g);
shortestPath_Floyd(g);
//show(g);
return 0;
}
思想就是判断顶点K在不在最短路径上,如果在最短路径上,就把他加入到pre中,并且更新最短路径。具体可以看这个视频。
这就是对图论中最短路径的总结。