【数据结构与算法】校园地图导航

实验名称

校园地图导航

实验内容

校园地图不低于五个点;

可以在代码里设置好点名,路径,路径权重;

程序运行,输入两个点,输出最短距离及最短路径;

加分项:可视化地图 QT。

实验目的

学会求两点之间最短路径的算法;

掌握深度优先搜索的算法和弗洛伊德算法;

应用图的遍历算法求解各种简单地图路径问题。

实验步骤

1.确定输入输出

依据给出的地图上的点,输入起点和终点;

输出两点之间最短距离以及两者之间相连的最短路径。

2.进行相关变量的定义和初始化

给定地图中的点(假设15个)存在数组path_1中

string vexname[num+1] = {"0.无",

    "1.西门", "2.树下空间", "3.图书馆", "4.信息北楼", "5.信息南楼", "6.二五广场",

    "7.体育馆", "8.田径场", "9.篮球场", "10.南海苑", "11.北海苑", "12.学生超市",

"13.东海苑", "14.五子顶", "15.综合楼"};

进行点与点之间边的初始化,初始化存在边的两个点及边的权重

int path_1[edge]={//两个点其中的第一个点

  0,1,2,5,5,6,6,2,2,2,3,3,3,15,15,15,14,14,13,13,13,10,9,9 };

实验步骤

int path_2[edge]={//两个点中对应的另一个点

    0,2,5,4,6,8,7,7,3,11,7,15,11,7,13,14,12,13,7,12,10,9,8,7 };

int path_Num[edge] = {两点之间边的权重

    0, 61, 24, 53, 15, 60, 9, 46, 46, 48,75, 50, 68, 96, 8, 17,4, 8, 15, 15, 108, 18, 75, 97 };

3.相关函数的编写

求最短距离的函数Floyd()

void floyd(){

    for(int k=1;k<=n;k++)

        for(int i=1;i<=n;i++)

            for(int j=1;j<=n;j++)

                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);

    for(int i=1;i<=n;i++){

        for(int j=1;j<=n;j++){

            if(d[i][j]>INF)cout<<"xxx ";

            else if(d[i][j]==inf)cout<<"000 ";

            else cout<<d[i][j]<<"  ";

        }

        cout<<endl;

    }

}

通过将地图相关信息(点、边和权重)保存到邻接矩阵中,通过邻接矩阵和弗洛伊德算法来求最短距离;不同于单源点最短路径算法——Dijkstra算法,Floyd算法可以求出一张图中任意两点的最短路径,思想是:两点之间的最短距离为两点之间的当前距离和引入中介节点后的距离之中取最短,邻接矩阵初始状态下,每对直接相连的顶点之间的距离为两者之间的边的权重。通过依次引入图中其他的点作为中介顶点,根据状态转移方程不断更新距离矩阵。这样最终我们可以得到图中任意两点之间的最短距离。

求两点间最短路径的函数dfs()

void dfs(int x,int y,int mid,int z){

    for(int i=1;i<=n;i++){

        if(!vis[i]&&mid+e[x][i]<=z){

            if(i==y){

                if(mid+e[x][i]==z){flag=1;return ;}

                else return;

            }

            else{

                vis[i]=1;

                que[0]++;que[que[0]]=i;

                dfs(i,y,mid+e[x][i],z);

                if(flag)return ;

                que[que[0]]=0;que[0]--;

                vis[i]=0;

            }

        }

    }

}

通过深度优先搜索来递归求最短的路径。从起点连接的所有结点开始遍历,如果当前路径长度mid加上边长后小于已知的最短路径长度,那么标记该点并加入到队列中,进行dfs,当找到结点为终点y,且距离等于最短距离z时,flag标记为1,一路回溯回去。最终将找到的最短路径从que队列中输出。

主函数中邻接矩阵的构建:

for(int i=1;i<=n;i++)d[i][i]=inf;

    for(int i=1;i<=m;i++){

        x=path_1[i];

        y=path_2[i];

        z=path_Num[i];

        d[x][y]=(d[x][y]<z?d[x][y]:z);

     }

通过初始化地图的点和边以及权重进行构建,初始化时全部设置为一个无穷大的值,便于求最短路径,要的是最小值。

1.测试案例

建成的邻接矩阵输出如下:

xxx表示不通,000无意义

当选择1.西门到8.田径场时,输出如下

实验总结

通过本次实验的完成,我更加熟悉了用邻接矩阵表示地图的方法,认识到了邻接矩阵和邻接表在数据结构中的重要性;同时我深刻的认识到了最短路径的求解方法,对于各种搜索方法以及求最短路径的方法有了更加深刻的理解,特别是对于弗洛伊德算法的本质有了更深的认识,并可以应用与算法中,对比单源点最短路径算法——Dijkstra算法,Floyd算法可以求出一张图中任意两点的最短路径,且允许图中存在负权重边的情况。可以说求两个点之间的最短路径最优算法就是Floyd了。总之,此次实验收获颇多,提升了自己。

参考代码:
 

//
//  main.cpp
//  地图最短路径
//
#include<iostream>
#include<algorithm>
#include<math.h>
#include<string.h>
#define INF 999999
#define inf 99999
#define max 205
#define num 16
#define edge 24
using namespace std;
int d[max][max],e[max][max],n,m;
string vexname[num+1] = {"0.无",
    "1.西门", "2.树下空间", "3.图书馆", "4.信息北楼", "5.信息南楼", "6.二五广场",
    "7.体育馆", "8.田径场", "9.篮球场", "10.南海苑", "11.北海苑", "12.学生超市",
    "13.东海苑", "14.五子顶", "15.综合楼"};
int path_1[edge]={
  0,1,2,5,5,6,6,2,2,2,3,3,3,15,15,15,14,14,13,13,13,10,9,9
};
int path_2[edge]={
    0,2,5,4,6,8,7,7,3,11,7,15,11,7,13,14,12,13,7,12,10,9,8,7
};
int path_Num[edge] = {
    0, 61, 24, 53, 15, 60, 9, 46, 46, 48,75, 50, 68, 96, 8, 17,4, 8, 15, 15, 108, 18, 75, 97
};
void floyd()
{
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(d[i][j]>INF)cout<<"xxx ";
            else if(d[i][j]==inf)cout<<"000 ";
            else cout<<d[i][j]<<"  ";
        }
        cout<<endl;
    }
}
int que[max],vis[max],flag;
void dfs(int x,int y,int mid,int z)
{
    for(int i=1;i<=n;i++)
    {
        if(!vis[i]&&mid+e[x][i]<=z)
        {
            if(i==y)
            {
                if(mid+e[x][i]==z){flag=1;return ;}
                else return;
            }
            else
            {
                vis[i]=1;
                que[0]++;que[que[0]]=i;
                dfs(i,y,mid+e[x][i],z);
                if(flag)return ;
                que[que[0]]=0;que[0]--;
                vis[i]=0;
            }
        }
    }
}
int main()
{
    int x,y,z;
    n=num;
    m=edge;
    memset(d,INF,sizeof(d));
    for(int i=1;i<=n;i++)d[i][i]=inf;
    for(int i=1;i<=m;i++)
    {
        x=path_1[i];
        y=path_2[i];
        z=path_Num[i];
        d[x][y]=(d[x][y]<z?d[x][y]:z);
     }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            e[i][j]=d[i][j];
    floyd();
    
    for(int i=0;i<num;i++)
    {
        cout<<vexname[i];
        cout<<" ";
    }
    cout<<endl;
    cout<<"地点信息如上图,请输入起点和终点(序号表示)"<<endl;
    cin>>x>>y;
    if(d[x][y]>inf)
        cout<<"两点之间无法到达!"<<endl;
    else
    {
        cout<<"最短距离为:"<<d[x][y]<<endl;
        cout<<"最短路径为:";
        que[0]=1;que[que[0]]=x;
        dfs(x,y,0,d[x][y]);
        for(int i=1;i<=que[0];i++)
            cout<<vexname[que[i]]<<"->";
        cout<<vexname[y]<<endl;
    }
    return 0;
}

  • 25
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值