第十三周项目3—Floyd算法验证没对定点之间的最短路径

本文介绍了一个使用Floyd算法求解图中所有顶点对之间的最短路径的C语言实现。通过具体的代码示例展示了如何利用二维数组存储图的边权,并通过Floyd算法更新最短路径矩阵和路径矩阵。此外,还提供了输出最短路径及其长度的方法。

问题及代码

这里写图片描述

#include <stdio.h>  
#include <malloc.h>  
#include "graph.h"  
#define MaxSize 100  
void Ppath(int path[][MAXV],int i,int j)  //前向递归查找路径上的顶点  
{  
    int k;  
    k=path[i][j];  
    if (k==-1) return;  //找到了起点则返回  
    Ppath(path,i,k);    //找顶点i的前一个顶点k  
    printf("%d,",k);  
    Ppath(path,k,j);    //找顶点k的前一个顶点j  
}  
void Dispath(int A[][MAXV],int path[][MAXV],int n)  
{  
    int i,j;  
    for (i=0; i<n; i++)  
        for (j=0; j<n; j++)  
        {  
            if (A[i][j]==INF)  
            {  
                if (i!=j)  
                    printf("从%d到%d没有路径\n",i,j);  
            }  
            else  
            {  
                printf("  从%d到%d=>路径长度:%d 路径:",i,j,A[i][j]);  
                printf("%d,",i);    //输出路径上的起点  
                Ppath(path,i,j);    //输出路径上的中间点  
                printf("%d\n",j);   //输出路径上的终点  
            }  
        }  
}  
void Floyd(MGraph g)  
{  
    int A[MAXV][MAXV],path[MAXV][MAXV];  
    int i,j,k;  
    for (i=0; i<g.n; i++)  
        for (j=0; j<g.n; j++)  
        {  
            A[i][j]=g.edges[i][j];  
            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][j]>A[i][k]+A[k][j])  
                {  
                    A[i][j]=A[i][k]+A[k][j];  
                    path[i][j]=k;  
                }  
    }  
    Dispath(A,path,g.n);   //输出最短路径  
}  
int main()  
{  
    MGraph g;  
    int A[4][4]=  
    {  
        {0,  5,INF,7},  
        {INF,0,  4,2},  
        {3,  3,  0,2},  
        {INF,INF,1,0}  
    };  
    ArrayToMat(A[0], 4, g);  
    Floyd(g);  
    return 0;  
}  



运行结果



//集美大学校园管理系统 #include<stdio.h> #include<stdlib.h> #include<string.h> #define Infinity 65535 //表示无穷大 #define MaxNumber 23 //用于邻接矩阵 #define vertex 15//顶点个数 typedef struct side//边的权值 { int wet;//权值 }side, wetmatrix[MaxNumber][MaxNumber];//边的邻接矩阵类型 typedef struct vetinf//顶点信息 { int number;//顶点编号 char name[64];//顶点名称 char intro[256];//顶点介绍 }vetinf; typedef struct mapstr//图结构信息 { vetinf vets[MaxNumber];//顶点数组 wetmatrix mat;//邻接矩阵 int vetnum, sidenum; }mapstr; //全局变量 mapstr campus;//图结构变量(学校校园) int d[30]; int visited[50]; int shortest[MaxNumber][MaxNumber];//定义全局变量存储最小路径 int pathh[MaxNumber][MaxNumber];//定义存储路径 //1.图的初始化 mapstr initmap() { mapstr m;//构件图m int i = 0, j = 0; m.vetnum = 15;//定义顶点个数 m.sidenum = 23;//定义边的条数 for (i = 1; i <= vertex; i++)//依次设置顶点信息 m.vets[i].number = i; //输入顶点信息 strcpy_s(m.vets[1].name, "端景楼"); strcpy_s(m.vets[1].intro, "学生住宿场所"); strcpy_s(m.vets[2].name, "万人餐厅"); strcpy_s(m.vets[2].intro, "为学生提供就餐场所"); strcpy_s(m.vets[3].name, "西苑餐厅"); strcpy_s(m.vets[3].intro, "为学生提供就餐场所"); strcpy_s(m.vets[4].name, "光前体育馆"); strcpy_s(m.vets[4].intro, "体育活动的场所"); strcpy_s(m.vets[5].name, "庄重文夫人体育中心"); strcpy_s(m.vets[5].intro, "体育场"); strcpy_s(m.vets[6].name, "引桐楼"); strcpy_s(m.vets[6].intro, "学生住宿场所"); strcpy_s(m.vets[7].name, "嘉庚图书馆"); strcpy_s(m.vets[7].intro, "图书馆"); strcpy_s(m.vets[8].name, "中山纪念楼"); strcpy_s(m.vets[8].intro, "纪念馆"); strcpy_s(m.vets[9].name, "勿忘亭"); strcpy_s(m.vets[9].intro, "可以看到学校的湖,景色优美"); strcpy_s(m.vets[10].name, "建发楼,美玲楼,禹洲楼,庄汉水楼"); strcpy_s(m.vets[10].intro, "教学楼"); strcpy_s(m.vets[11].name, "尚大楼"); strcpy_s(m.vets[11].intro, "学校的办公楼,也是最高的楼"); strcpy_s(m.vets[12].name, "陈延奎图书馆"); strcpy_s(m.vets[12].intro, "学校里最大的图书馆"); strcpy_s(m.vets[13].name, "陈嘉庚先生雕像"); strcpy_s(m.vets[13].intro, "位于学校东门"); strcpy_s(m.vets[14].name, "章辉楼"); strcpy_s(m.vets[14].intro, "学校的教学楼,也是理学院的办公楼"); strcpy_s(m.vets[15].name, "南大门"); strcpy_s(m.vets[15].intro, "学校最大的门,对面是万达广场"); for (i = 1; i <= vertex; i++) for (j = 1; j <= vertex; j++) m.mat[i][j].wet = Infinity;//初始化图的邻接矩阵 m.mat[1][2].wet = 80; m.mat[1][3].wet = 80; m.mat[3][4].wet = 60; m.mat[1][5].wet = 150; m.mat[2][5].wet = 70; m.mat[3][6].wet = 180; m.mat[6][7].wet = 60; m.mat[6][8].wet = 60; m.mat[4][8].wet = 40; m.mat[7][13].wet = 200; m.mat[7][9].wet = 50; m.mat[9][13].wet = 180; m.mat[9][10].wet = 140; m.mat[8][10].wet = 190; m.mat[10][11].wet = 40; m.mat[10][12].wet = 45; m.mat[11][12].wet = 25; m.mat[11][14].wet = 60; m.mat[12][14].wet = 40; m.mat[14][15].wet = 150; m.mat[11][15].wet = 205; m.mat[13][15].wet = 210; for (i = 1; i <= vertex; i++)//无向带权图是对称矩阵,给其另一半赋值 for (j = 1; j <= vertex; j++) m.mat[j][i].wet = m.mat[i][j].wet; return m; } //2.查询景点在图中的序号 int locatevet(mapstr m, int v) { int i; for (i = 0; i <= m.vetnum; i++) if (v == m.vets[i].number) return i;//找到返回顶点i return -1;//未找到 } //3.查询输入序号l,n间的长度不超过10个景点的路径 void path(mapstr m, int l, int n, int k) { int s, t = k + 1; int length = 0;//t用于存储路径上下一顶点对应的d[]数组元素的下标 if (d[k] == n && k < 8)//若d[k]是终点且景点个数<8,则输出该路径 { for (s = 0; s < k; s++) { length = length + m.mat[d[s]][d[s + 1]].wet; } if (length < 4000)//打印路径小于200(定长)的路径 { for (s = 0; s < k; s++)//输出该路径,s=0时为起点m { printf("%d%s--->", d[s], m.vets[d[s]].name); } printf("%d%s ", d[s], m.vets[d[s]].name);//输出最后一个顶点 printf("总路线长为%d米\n\n", length); } } else { s = 1; while (s <= m.vetnum)//从第m个顶点,访问所有顶点是否有路径 { if ((m.mat[d[k]][s].wet < Infinity) && (visited[s] == 0))//顶点有边且未被访问 { visited[s] = 1; d[k + 1] = s;//存储顶点编号 path(m, l, n, t); visited[s] = 0;//将找到的路径上的顶点的访问标志重新设置为,便于探究新的路径 } s++;//试验下一顶点s开始是否有到终点的路径; } } } //4.查询两景点的所有路径 int allpath(mapstr m) { int k, i, j, l, n; printf("\n\n请输入您想要查询的两个景点的编号:\n\n"); scanf_s("%d%d", &i, &j); printf("\n\n"); l = locatevet(m, i);//locatevet 确定该顶点是否存在。若存在,返回该顶点编号。 n = locatevet(m, j); d[0] = l;//路径起点l(字母).(d[]数组为全局变量) for (k = 0; k < vertex; k++) visited[k] = 0; visited[l] = 1; path(m, l, n, 0); return 1; } //5.迪杰斯特拉算法求单源最短路径 void shortestpath(mapstr m) { int v0, v, w, k = 1, min, t, p; int final[MaxNumber];//final[w]=1表示已经求得顶点V0到Vw的的最短路径 int Pathside[MaxNumber];//用于存储最短路径下标的数组 int ShortPathwet[MaxNumber];//用于存储到各点最短路径的权值和 printf("\n请输入起始景点的编号:"); scanf_s("%d", &v0); printf("\n\n"); while (v0<0 || v0>vertex)//判断是否输入正确 { printf("\n您输入的景点编号不存在\n"); printf("请重新输入:"); scanf_s("%d", &v0); } for (v = 1; v <= m.vetnum; v++)//数组初始化 { final[v] = 0;//全部顶点初始化为未找到路径 ShortPathwet[v] = m.mat[v0][v].wet;//将与v0有连线的路径加上权值 Pathside[v] = 0;//初始化路径数组为0 } ShortPathwet[v0] = 0; final[v0] = 1; //Dijkstr算法主体 for (v = 1; v <= m.vetnum; v++) { min = Infinity; for (w = 1; w <= m.vetnum; w++)//找出离当前指向顶点最近的点 { if (!final[w] && ShortPathwet[w] < min)//未被访问且存在边 { k = w; min = ShortPathwet[w]; } } final[k] = 1;//将找到的离当前顶点最近的置1 //修正 for (w = 1; w <= m.vetnum; w++) { if (!final[w] && (min + m.mat[k][w].wet < ShortPathwet[w])) { ShortPathwet[w] = min + m.mat[k][w].wet;//修改当前最优路径长度 Pathside[w] = k;//存放前驱结点 } } } printf("打印P数组:"); //打印p数组 for (t = 1; t <= m.vetnum; t++) { printf("%d ", Pathside[t]); } printf("\n\n"); printf("打印S数组:"); //打印s数组 for (t = 1; t <= m.vetnum; t++) { printf("%d ", ShortPathwet[t]); } printf("\n\n"); //打印最短路径 for (t = 1; t <= m.vetnum; t++) { p = t; if (t != v0) { printf("%d%s", t, m.vets[t].name); for (w = 1; w <= m.vetnum; w++) { if (Pathside[p] != 0) { printf("<--%d%s", Pathside[p], m.vets[Pathside[p]].name); p = Pathside[p]; } } printf("<--%d%s", v0, m.vets[v0].name); printf("\n总路线长为%d米\n\n", ShortPathwet[t]); } } } //6.主页 void menu() { printf(" ┌──────────────────────────────────────────────────────┐\n"); printf(" │ ╭ ═══════════════════════════════════════════════ ╮ │\n"); printf(" │ ││ 欢 迎 使 用 校 园 导 游 系 统 ││ │\n"); printf(" │ ╰ ═══════════════════════════════════════════════ ╯ │\n"); printf(" │ 欢迎来到 │\n"); printf(" │ 集美大学 │\n"); printf(" │ 菜 单 选 择 │\n"); printf(" │ *************************************************** │\n"); printf(" │ * 1.主页 ** 2.查看游览路线 * │\n"); printf(" │ *************************************************** │\n"); printf(" │ * 3.查询景点间最短路径 ** 4.查询景点间所有路径* │\n"); printf(" │ *************************************************** │\n"); printf(" │ * 5.学校景点介绍 ** 6.更改图信息 * │\n"); printf(" │ *************************************************** │\n"); printf(" │ * 0.退出 * │\n"); printf(" │ *************************************************** │\n"); printf(" └──────────────────────────────────────────────────────┘\n"); } //以下是修改图的相关信息。 //7.增加一条边 int incside(mapstr* m) { int l, n, distance; printf("\n请输入边的起点和终点编号,权值:"); scanf_s("%d%d%d", &l, &n, &distance); while (l<0 || l>m->vetnum || n<0 || n>m->vetnum) { printf("输入错误,请重新输入"); scanf_s("%d %d", &l, &n); } if (locatevet(campus, l) < 0) { printf("此节点%d已删除", l); return 1; } if (locatevet(campus, n) < 0) { printf("此节点%d已被删除", n); return 1; } m->mat[l][n].wet = distance; m->mat[n][l].wet = m->mat[l][n].wet; m->sidenum++; return 1; } //8.增加一个结点 int incvet(mapstr* m) { int i; m->vetnum++;//顶点数加一 printf("请输入您要增加结点的信息:"); printf("\n编号:"); scanf_s("%d", &m->vets[m->vetnum].number); printf("名称:"); scanf_s("%s", m->vets[m->vetnum].name,10); printf("简介:"); scanf_s("%s", m->vets[m->vetnum].intro,20); for (i = 1; i <= m->vetnum; i++) { m->mat[m->vetnum][i].wet = Infinity; m->mat[i][m->vetnum].wet = Infinity; } return 1; } //9.删除一个结点 int delvet(mapstr* m) { int i = 0, j, l, v; if (m->vetnum <= 0) { printf("图中已无顶点"); return 1; } printf("\n下面请输入您要删除的景点编号:"); scanf_s("%d", &v); while (v<0 || v>m->vetnum) { printf("\n输入错误!请重新输入:"); scanf_s("%d", &v); } l = locatevet(campus, v); if (l < 0) { printf("顶点%d已删除\n", v); return 1; } for (i = l; i <= m->vetnum - 1; i++) for (j = 1; j <= m->vetnum; j++)//将二维数组中的第m+1行依次向前移动一行(删除第m行) m->mat[i][j] = m->mat[i + 1][j]; for (i = l; i <= m->vetnum - 1; i++) for (j = 1; j <= m->vetnum; j++)//将二维数组中的第m+1列依次向前移动一列(删除第m列) m->mat[j][i] = m->mat[j][i + 1]; m->vets[v].number = -1;//表示此点已删除,后期打印也不会显示该点 m->vetnum--;//顶点个数-1 return 1; } //10.删除一条边 int delside(mapstr* m) { int l, n, v0, v1; if (m->vetnum <= 0) { printf("图中有边了,无法删除"); return 1; } printf("\n下面请输入您要删除的边的起点和终点编号:"); scanf_s("%d %d", &v0, &v1); l = locatevet(campus, v0); if (m->vetnum < 0) { printf("此%d顶点已删除", v0); return 1; } n = locatevet(campus, v1); if (n < 0) { printf("此%d顶点已删除", v1); return 1; } m->mat[l][n].wet = Infinity;//将删掉的边的权值改为无穷 m->mat[n][l].wet = Infinity; m->sidenum--;//图的边数减一 return 1; } //11.重新构造图 int creatmap(mapstr* m) { int i, j, l, n, v0, v1, distance; printf("请输入图的顶点数和边数:\n"); scanf_s("%d %d", &m->vetnum, &m->sidenum); printf("请输入顶点信息: \n"); for (i = 1; i <= m->vetnum; i++)//输入各顶点对应的景点信息 { printf("请输入景点编号:"); scanf_s("%d", &m->vets[i].number); printf("请输入景点名称:"); scanf_s("%s", &m->vets[i].name,10); printf("请输入景点简介:"); scanf_s("%s", &m->vets[i].intro,20); } for (i = 0; i <= m->vetnum; i++)//权值初始化为无穷 for (j = 0; j <= m->vetnum; j++) m->mat[i][j].wet = Infinity; printf("请输入图中各景点边的信息 \n"); for (i = 1; i <= m->sidenum; i++) { printf("\n请输入第%d条边的起点,终点,长度为:", i); scanf_s("%d %d %d", &v0, &v1, &distance); l = locatevet(campus, v0); n = locatevet(campus, v1); if (l > 0 && n > 0) { m->mat[l][n].wet = distance; m->mat[n][l].wet = m->mat[l][n].wet; } } return 1; } //12.更改图部分信息 int newmap(mapstr* m) { int changenum, i, l, n, t, distance, v0, v1; printf("\n下面请输入你要修改的景点的个数:\n");//修改定点对应的景点 scanf_s("%d", &changenum); while (changenum<0 || changenum>vertex) { printf("\n你的输入有误,请重新输入"); scanf_s("%d", &changenum); } for (i = 0; i < changenum; i++) { printf("\n请输入景点编号:"); scanf_s("&d", &l); t = locatevet(campus, l); printf("\n请输入修改后景点的名称:"); scanf_s("%s", &m->vets[t].name,10); printf("\n请输入修改后景点的简介:"); scanf_s("%s", &m->vets[t].intro,20); } printf("\n下面请输入你要修改的边的个数"); scanf_s("%d", &changenum); while (changenum<0 || changenum>vertex); { printf("\n你的输入有误,请重新输入"); scanf_s("%d", &changenum); } if (changenum != 0) printf("\n下面请输入更新边的信息:\n"); for (i = 1; i <= changenum; i++) { printf("\n修改的第%d条边的起点 终点 长度为:", i); scanf_s("%d %d %d", &v0, &v1, &distance); l = locatevet(campus, v0); n = locatevet(campus, v1); if (l >= 0 && n >= 0) { m->mat[l][n].wet = distance; m->mat[n][l].wet = m->mat[l][n].wet; } } return 1; } //13.输出图的邻接矩阵的值 void printmapstr(mapstr m) { int i, j, k = 0; for (i = 1; i <= vertex; i++) { if (m.vets[i].number != -1) printf("%6d", i); } printf("\n"); for (i = 1; i <= m.vetnum; i++) { for (j = 1; j <= m.vetnum; j++) { if (m.mat[i][j].wet == Infinity) printf(" **** "); else printf("%6d", m.mat[i][j].wet); k++; if (k % m.vetnum == 0) printf("\n"); } } } //14.图的操作主函数 int changemap(mapstr* m) { int choice; printf("(1)增加结点 (2)删除结点 \n"); printf("(3)删除边 (4) 增加边 \n"); printf("(5)输出邻接矩阵 (6)重新建图 \n"); printf("(7)更新信息 (8)返回主页 \n"); do { printf("\n请输入你的选择:"); scanf_s("%d", &choice); switch (choice) { case 1:incvet(m); break; case 2:delvet(m); break; case 3:delside(m); break; case 4:incside(m); break; case 5:printmapstr(campus); break; case 6:creatmap(m); break; case 7:newmap(m); break; case 8:system("cls"); menu(); return 1; default:printf("未找到该功能,请输入有效选项!\n"); break; } } while (choice); } //15.用户登录 int userlog() { int i; int a[6] = { 1,2,3,4,5,6 }, b[6]; printf("\n请输入六位密码(用空格隔开):\n"); for (i = 0; i < 6; i++) scanf_s("%d", &b[i]); for (i = 0; i < 6; i++) { if (a[i] != b[i]) { printf("密码错误!自动返回主页面\n"); menu(); return 0; } } printf("密码正确,登陆成功!\n\n"); changemap(&campus); } //16.弗洛伊德算法 void floyd(mapstr m) { int i, j, k; for (i = 1; i <= vertex; i++)//将图的邻接矩阵赋值给 shortest二维数组,将矩阵pathh全部初始化为-1 { for (j = 1; j <= vertex; j++) { shortest[i][j] = m.mat[i][j].wet; pathh[i][j] = j; } } int ii, jj, k1 = 0; for (ii = 1; ii <= vertex; ii++) printf("%6d", ii);//横着标号1到11 printf("\n"); for (ii = 1; ii <= vertex; ii++) { printf("%d", ii); for (jj = 1; jj <= vertex; jj++) { printf("%6d", pathh[ii][jj]); k1++; if (k1 % vertex == 0) printf("\n"); } } printf("\n\n\n"); for (k = 1; k <= vertex; k++)//核心操作,完成了以k为中间点对所有的顶点对(i,j)进行检测和修改 { for (i = 1; i <= vertex; i++) { for (j = 1; j <= vertex; j++) { if (shortest[i][j] > shortest[i][k] + shortest[k][j]) { shortest[i][j] = shortest[i][k] + shortest[k][j]; pathh[i][j] = pathh[i][k];//记录一下所走的路 //P数组用来存放前驱顶点 } } } } } //17.输出数组 void printarray() { int i, j, k = 0; for (i = 1; i <= vertex; i++) printf("%6d", i);//横着标号0-11 printf("\n"); for (i = 0; i <= vertex; i++) { printf("%d", i);//竖着标号0-11 for (j = 1; j <= vertex; j++) { printf("%6d", pathh[i][j]); k++; if (k % vertex == 0) printf("\n"); } } printf("\n\n\n"); } //18.输出最短路径 void display(mapstr m, int i, int j) { int a, b; a = i, b = j; printf("您要查询的两景点间最短路径:\n\n"); printf("%d%s", a, m.vets[a].name); while (pathh[i][j] != b) { printf("-->%d%s", pathh[i][j], m.vets[pathh[i][j]].name); i = pathh[i][j]; } printf("-->%d%s\n\n", b, m.vets[b].name); printf("%s-->%s的最短路径是:%d米\n\n", m.vets[a].name, m.vets[b].name, shortest[a][b]); } //19.任意两点间距离(16-19) int shortdistance(mapstr m) { int i, j; printf("请输入要查询的两个景点的数字编号(用空格隔开)\n"); scanf_s("%d %d", &i, &j); if (i<0 || i>vertex || j<0 || j>vertex) { printf("输入信息有误!\n\n"); printf("请输入要查询的两个景点的数字编号(用空格隔开)\n"); scanf_s("%d %d", &i, &j); } else { floyd(m); printarray(); display(m, i, j); } return 1; } //20.显示所有景点信息 void compusinfor(mapstr m) { int i; printf(" \n\n编号 景点名称 简介\n"); printf("****************************************************************************\n"); for (i = 1; i <= m.vetnum; i++) { if (m.vets[i].number != -1) printf("%-10d%-40s%-70s\n", m.vets[i].number, m.vets[i].name, m.vets[i].intro); } printf("****************************************************************************\n"); } //21.用户界面 void mainwork() { menu(); int choice; campus = initmap(); do { printf("请输入你的选择:"); scanf_s("%d", &choice); switch (choice) { case 1:system("cls"); menu(); break; case 2:system("cls"); shortestpath(campus); break; case 3:system("cls"); shortdistance(campus); break; case 4:system("cls"); allpath(campus); break; case 5:system("cls"); compusinfor(campus); break; case 6:system("cls"); userlog(); break; case 0:system("cls"); printf("谢谢使用\n"); break; default:printf("未找到该功能,请输入有效选项!\n"); break; } } while (choice); } int main() { mainwork(); return 0; } 解释一下所有程序
最新发布
06-18
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值