最短路径及最低成本算法实现模型

 
在vs环境下进行的操作

用两种方法分别模拟实现公园导航
1.Dijkstra算法
按路径长度递增次序来产生最短路径算法;
    dist【】距离, path【】前结点
    ①初始化
    ②找最小距离
    ③修正a到c,a到b再到c的距离
2。Floyd算法
邻接矩阵迭代
Dijkstra算法可实现单源点到其他所有点的的最短路径,也可用于所有点到所有点,较为灵活,但相对较复杂(一开始模拟时以为是所有点到所有点)
Floyd算法主要是所有点到所有点,但较好理解

在用Dijkstra算法时,一开始函数定义为Dijkstra(MGraph * g, int v)参数g为地图,v为单元点,但函数内部的数组s[]运行后报错Run-Time Check Failure #2 - Stack around the variable 's' was corrupted.推测为下标越界或溢出,但逻辑本身应该是没问题的,我也不知为何。
但将数组置为全局则不报错;推测变量在栈区(最多只可以开2M)?,而之后放到全局区可以开的空间大很多,就不会溢出? 
报错参考https://blog.csdn.net/chenyujing1234/article/details/8261914


两种方法求管道修建最低成本
1.prim算法(时间复杂度O(n^2))n,为顶点数
将图分为两个顶点集,一个为已选顶点,一个为未选顶点,每次从 未选顶点集合里面 抽出 到  已选顶点集合里面 的 最小权;直到所有被选。
2.kruskal算法(算法实现略过)
边的算法,将边归并,适合稀疏网



 #include <iostream>
#include <windows.h>
 
#define MAX 50
#define INF 32767
 
//顶点类型
typedef struct {
int num;//景点编号
char info[MAX];//景点名称
char introduction[MAX];//景点简介
}vertexType;
 
//图的定义
typedef struct {
int deges[MAX][MAX];//邻接矩阵
int n, e;//顶点数,弧数
vertexType vexs[MAX];//存放顶点信息
}MGraph;
 
void menu1();//菜单
 
MGraph *create(MGraph *g, int(*a)[MAX]);//建图
void disp(MGraph* g);//输出图
 
void Dijkstra(MGraph *g, int v,int s[]);//Dijkstra算法
void ppath(MGraph *g, int path[], int i, int v);//计算最短路径长度
void DisPath(MGraph *g, int dist[], int path[], int s[], int n, int v);//输出从V出发的所有最短路径
 
void Floyd(MGraph *g);//Floyd算法
void Dispath(MGraph *g, int A[][MAX], int path[][MAX]);//输出所有最短路径

void Prim(MGraph *g, int v);//普里姆算法求管道修建最低成本

int s[MAX];
 
int main()
{
int c;
int change = 1;
MGraph *g = NULL;
int A[MAX][MAX] = {
 
{0,45,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,400,INF,INF,INF,210,150},
{45,0,70,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,70,0,40,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,40,0,50,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,50,0,40,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,40,0,350,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,350,0,30,INF,INF,36,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,30,0,38,34,INF,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,38,0,INF,INF,INF,INF,INF,22,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,34,INF,0,15,INF,INF,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,36,INF,INF,15,0,INF,INF,15,INF,INF,18,INF,INF},
{400,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,0,34,INF,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,34,0,35,24,36,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,15,INF,35,0,INF,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,22,INF,INF,INF,24,INF,0,INF,INF,INF,INF},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,36,INF,INF,0,INF,INF,40},
{INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,18,INF,INF,INF,INF,INF,0,95,INF},
{210,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,95,0,45},
{150,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,INF,40,INF,45,0} };
 
menu1();
g = create(g, A);
 
while (change)
{
int u = 0;
printf("         请选择(1-5):");
scanf_s("%d", &c);
switch (c)
{
case 1:
disp(g);
break;
case 2:printf("\n求单源景点的最短路径:\n\n");
printf("\n    请输入出发点:");
scanf_s("%d", &u);
Dijkstra(g, u, s);
printf("\n");
break;
case 3:printf("\n求任意两景点之间的最短路径:\n\n");
Floyd(g);
printf("\n");
break;
case 4:change = 0;
printf("已退出!");
break;
 
}
}
printf("\n");
return 0;
}
 
//邻接矩阵创建图
MGraph * create(MGraph * g, int(*a)[MAX])
{
int i = 0;
g = (MGraph*)malloc(sizeof(MGraph));
g->n = 19; g->e = 24;
FILE *fp1;
fopen_s(&fp1,"F:\\v4.txt","r+");
while (!feof(fp1))
{
g->vexs[i].num = i;
fscanf_s(fp1,"%s %s",g->vexs[i].info, _countof(g->vexs[i].info),g->vexs[i].introduction, _countof(g->vexs[i].introduction));
i++;
}
 
for (int j = 0; j < g->n; j++)
{
for (int k = 0; k < g->n; k++) {
g->deges[j][k] = *(a[j] + k);
}
}
return g;
}
//输出图
void disp(MGraph * g)
{
int i, j, k = 0;
 
printf("    公园的景点:\n");
for (i = 0; i < g->n; i++)
printf("%d:%s\n", i, g->vexs[i].info);
 
 
printf("\n输出公园地图的信息(邻接矩阵表示):\n");
printf("    0    1    2    3    4    5    6    7    8    9    10   11   12   13    14   15   16   17    18\n");
for (i = 0; i < g->n; i++)
{
printf(" %-3d|", i);   //输出格式
for (j = 0; j < g->n; j++)
{
k++;
if (g->deges[i][j] == INF)       //两顶点之间无边的处理
printf("∞   ");
else
printf("%-3d  ", g->deges[i][j]);  //两顶点之间有边的处理
if (k % 19 == 0) { printf(" |\n"); }    //输出格式
}
 
}
}
 
//狄杰斯特拉算法从顶点v到其余各顶点的最短路径
 
void Dijkstra(MGraph * g, int v, int s[])
{
int dist[MAX], path[MAX];//路径每个点存放之前的一个点,dist存放2个点之间的距离;
 
int mindis;//最小距离
int i, j, k, u, n = g->n;
 
for (i = 0; i < n; i++) {
dist[i] = g->deges[v][i];
s[i] = 0;
if (g->deges[v][i] < INF) {
path[i] = v;
}
else {
path[i] = -1;
}
}
 
s[v] = 1; path[v] = 0;
 
for (i = 0; i < n; i++) {
mindis = INF;
u = -1;
for (j = 0; j < n; j++) {
if (s[j] == 0 && dist[j] < mindis) {
mindis = dist[j];
u = j;
}
}
s[u] = 1;
for (k = 0; k < n; k++) {
if (s[k] == 0) {
if (g->deges[u][k] < INF  && dist[u] + g->deges[u][k] < dist[k]) {
dist[k] = dist[u] + g->deges[u][k];
path[k] = u;
}
}
}
}
printf(" \n    输出最短路径:\n");
DisPath(g, dist, path, s, n, v);  //输出最短路径
}
 
//v到i的最短路径,输出中间路径
void ppath(MGraph * g, int path[], int i, int v)
{
int k;
k = path[i];
if (k == v) {
return;
}
ppath(g, path, k, v);
printf("%s ——>", g->vexs[k].info);
}
 
//由path计算v到所有点最短路径
void DisPath(MGraph * g, int dist[], int path[], int s[], int n, int v)
{
int i;
printf(" --------------------------------------------------------------\n");
for (i = 0; i < n; i++) {
if (s[i] == 1) {
if (i != v) {
Sleep(150);
printf("从%s到%s的最短路径长度为:%d       \t路径为:", g->vexs[v].info, g->vexs[i].info, dist[i]);
 
printf("%s ——>", g->vexs[v].info);
ppath(g, path, i, v);
printf("%s \n", g->vexs[i].info);
}
}
else
{
printf("  从%d到%d不存在路径\n", v, i);
}
}
printf("\n--------------------------------------------------------------\n\n");
}
 
//Floyd算法
void Floyd(MGraph * g)
{
int i, j, k;
int a[MAX][MAX]; int path[MAX][MAX];
//初始化a&path;
for (i = 0; i < g->n; i++) {
for (j = 0; j < g->n; j++)
{
a[i][j] = g->deges[i][j];
if (g->deges[i][j] < INF && i != j) {
path[i][j] = i;
}
else
{
path[i][j] = -1;
}
}
}
 
for (k = 0; k < g->n; k++) {
for (i = 0; i < g->n; i++)
{
for (j = 0; j < g->n; j++)
{
if (a[i][k] + a[k][j] < a[i][j]) {
a[i][j] = a[i][k] + a[k][j];
path[i][j] = path[k][j];
}
}
}
}
Dispath(g, a, path);
}
 
//重载由path计算v到所有点最短路径
void Dispath(MGraph * g, int A[][MAX], int path[][MAX])
{
int i, j, k, s;
int apath[MAX],d;
for (i = 0; i < g->n; i++)
{
for (j = 0; i < g->n; j++)
{
if (A[i][j] != INF && i != j) {
printf("  从%d到%d的路径为:", i, j);
k = path[i][j];
d = 0;
apath[d] = j;//添加起点
while (k != -1 && k != i)
{
d++;
apath[d] = k;
k = path[i][k];
}
d++; apath[d] = i;//添加终点
printf("%d", apath[d]);//输出起点
for (s = d - 1; s >= 0; s--)//输出路径上的中间顶点
printf(",%d", apath[s]);
printf("\t\t路径长度为:%d\n", A[i][j]);
}
}
 
}
}
 
//菜单
void menu1()
{
printf("\n");
printf("                 ******公园导游程序设计******\n");
printf("        ============================================\n");
printf("                   1.公园景点介绍\n");
printf("                   2.求单源景点的最短路径\n");
printf("                   3.求任意两景点之间的最短路径\n");
printf("                   4.退出 :\n");
printf("        =============================================\n");
}


//普里姆算法求管道修建最低成本
void Prim(MGraph * g, int v)
{
int min, sum = 0;
int lowcost[MAX];//低成本
int closest[MAX];//临近点
int u, i, j, k, n = g->n;
 
for (i = 0; i < n; i++) {
lowcost[i] = g->edges[v][i];
closest[i] = v;
}
 
for (i = 1; i < n; i++)
{
min = INF;
for (j = 0; j < n; j++) {
if (lowcost[j] != 0 && lowcost[j] < min) {
min = lowcost[j];
u = j;
}
}
printf("   线路:%s->%s", g->vexs[closest[u]].info,g->vexs[u].info); Sleep(200);
printf("    \t\t距离:%-dm .\n", min);
Sleep(30);
sum = sum + min;
 
lowcost[u] = 0;
 
for ( k = 0; k < n; k++)
{
if (g->edges[u][k] != 0 && g->edges[u][k] < lowcost[k]) {
lowcost[k] = g->edges[u][k];
closest[k] = u;
}
}
}
printf("\n   线路总距离为:%dm!", sum);
}
posted @ 2022-11-11 19:54  août  阅读(272)  评论(0)    收藏  举报