最短路径及最低成本算法实现模型
在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);
}
|