校园导游系统

点右上角关注一下呗~~

[基本要求]
1、 设计你的学校的校园平面图,所含景点10-15个。以图中顶点表示校园内各景点,存放景点名称、代号、简介等信息;以边表示路径,存放路径长度等相关信息。
2、 为来访客人提供图中任意景点相关信息的查询。
3、 为来访客人提供图中任意景点的问路查询,即查询任意两个景点之间的一条最短的简单路径。
4、 提供图中任意景点问路查询,即求任意两个景点之间的所有路径。
5、 提供校园图中多个景点的最佳访问路线查询,即求途经这多个景点的最佳路径。
6、 区分汽车线路与步行线路。
7、 设计一实用的查询界面和功能菜单。

1 课题描述

设计校园平面图,包含景点15个,道路多条,有人行道,有行车道,以顶点表示景点,边表示道路,可以查询任意两点的最短路径,所有路径,还有途经多点的最短路。

2 问题分析和任务定义

首先需要画出学校大致平面图,并标号编号名称,路径长度:

还需要写多个被调函数实现求最短路径,所有路径,途经多点最短路径的要求。

图有点丑~~

 

 

3 逻辑设计

 

为了实现以上4个功能,需要设计这些函数:

int mapp[16][16];//步行;

int mapp1[16][16];//驾车

int dis[16],vis[16];

int path[20];

void init();//最初将长度存好

void Query();//查询景点编号,信息,简介

void Query1();//查询两点任意最短路径及长度;

void DIS(int a,int b,int c);//计算dis数组

void dijstra(int b,int a,int c);//回溯求最短路径

void Query2();//查询两点所有路径

void QQ(int a);//最佳路径

void Query3();//查询途经多点的最短路径

void menu();//实现菜单功能

4 详细设计

用邻接矩阵存储图,因为要区分人行道和行车道,所以用两个矩阵存储。

为了实现两点最短路径,需要用到改进的dijstra算法,改进是指加上回溯求得最短路径,原始dijstra的算法只是求得最短路径的长度。

为了实现求任意两点所有路径的算法,需要用到DFS(深度优先搜索),但是求得所有路径会有很多条,这就需要筛选一下,选择几个输出。

为了实现途径多点的最短路径,同样需要用到DFS,在每个求得的路径遍历看是否经过了所要求的点,找出长度最小的输出。

5 程序编码

里面有双重队列哟!

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <string>
#include <stack>
#include <deque>
using namespace std;
#define MAX 0x3f3f3f
stack<int> S;
deque <int> dq;
deque <deque<int> > dd;
int mapp[16][16];//步行;
int mapp1[16][16];//驾车
int dis[16],vis[16];
int path[20];
int flag[200]= {0};
int e=0;
int aa[20]= {0};
void init();//最初将长度存好
void Query();//查询景点编号,信息,简介
void Query1();//查询两点任意最短路径及长度;
void DIS(int a,int b,int c);//计算dis数组
void dijstra(int b,int a,int c);//回溯求最短路径
void Query2();//查询两点所有路径
void QQ(int a);//最佳路径
void Query3();//查询途经多点的最短路径
void menu();//实现菜单功能
void init()
{
    memset(mapp,MAX,sizeof(mapp));
    memset(mapp1,MAX,sizeof(mapp));
    memset(dis,MAX,sizeof(dis));
    memset(vis,0,sizeof(vis));
    mapp[1][2]=mapp[2][1]=80;
    mapp[1][3]=mapp[3][1]=100;
    mapp[1][12]=mapp[12][1]=80;
    mapp[1][15]=mapp[15][1]=30;
    mapp[2][3]=mapp[3][2]=100;
    mapp[3][4]=mapp[4][3]=70;
    mapp[3][12]=mapp[12][3]=100;
    mapp[4][5]=mapp[5][4]=40;
    mapp[4][7]=mapp[7][4]=100;
    mapp[5][6]=mapp[6][5]=150;
    mapp[6][8]=mapp[8][6]=200;
    mapp[7][8]=mapp[8][7]=50;
    mapp[7][10]=mapp[10][7]=50;
    mapp[7][11]=mapp[11][7]=20;
    mapp[8][9]=mapp[9][8]=20;
    mapp[8][10]=mapp[10][8]=30;
    mapp[9][10]=mapp[10][9]=40;
    mapp[9][14]=mapp[14][9]=40;
    mapp[10][11]=mapp[11][10]=20;
    mapp[10][14]=mapp[14][10]=30;
    mapp[11][12]=mapp[12][11]=70;
    mapp[12][13]=mapp[13][12]=20;
    mapp[12][15]=mapp[15][12]=50;
    mapp[13][14]=mapp[14][13]=20;
    mapp1[1][3]=mapp1[3][1]=120;
    mapp1[1][12]=mapp1[12][1]=80;
    mapp1[12][11]=mapp1[11][12]=70;
    mapp1[1][13]=mapp1[13][1]=100;
    mapp1[1][15]=mapp1[15][1]=30;
    mapp1[3][4]=mapp1[4][3]=70;
    mapp1[4][5]=mapp1[5][4]=40;
    mapp1[5][6]=mapp1[6][5]=150;
    mapp1[6][8]=mapp1[8][6]=200;
    mapp1[6][9]=mapp1[9][6]=300;
    mapp1[9][14]=mapp1[14][9]=40;
    mapp1[13][14]=mapp1[14][13]=20;
//    int i,j,k;
//    for(k=1;k<=15;k++)
//        for(i=1;i<=15;i++)
//           for(j=1;j<=15;j++)
//              if(mapp[i][j]>mapp[i][k]+mapp[k][j])
//                  mapp[i][j]=mapp[i][k]+mapp[k][j];
//    for(k=1;k<=15;k++)
//        for(i=1;i<=15;i++)
//           for(j=1;j<=15;j++)
//              if(mapp1[i][j]>mapp1[i][k]+mapp1[k][j])
//                  mapp1[i][j]=mapp1[i][k]+mapp1[k][j];

}
void Query()
{
    int a;
    cout<<"=========景点编号========="<<endl;
    cout<<"= 1. 东门       2. 操场  ="<<endl;
    cout<<"= 3. 一餐       4. 二餐  ="<<endl;
    cout<<"= 5. 三餐       6. 南门  ="<<endl;
    cout<<"= 7. 图书馆     8. 大活  ="<<endl;
    cout<<"= 9. 办公楼     10.四教  ="<<endl;
    cout<<"= 11.二教       12.一教  ="<<endl;
    cout<<"= 13.三教       14.五教  ="<<endl;
    cout<<"=15. 体育馆              ="<<endl;
    cout<<"========================="<<endl;
    cout<<"输入你想查询景点信息的编号(1 ~ 15):";
    cin>>a;
    if(a==1)
        cout<<"* 山东工商学院大门,因面朝东面被称为东门!"<<endl;
    if(a==2)
        cout<<"* 操场有400米跑道,足球场,可以进行户外活动!"<<endl;
    if(a==3)
        cout<<"* 山东工商学院第一餐厅!"<<endl;
    if(a==4)
        cout<<"* 山东工商学院第二餐厅!"<<endl;
    if(a==5)
        cout<<"* 山东工商学院第三餐厅(东苑餐厅)!"<<endl;
    if(a==6)
        cout<<"* 山东工商学院南门,面朝南面得名!"<<endl;
    if(a==7)
        cout<<"* 图书馆可以借书,上自习,进入需刷校园卡!"<<endl;
    if(a==8)
        cout<<"* 大学生艺术活动中心,举办大型活动!"<<endl;
    if(a==9)
        cout<<"* 俗称七教,学校领导办公的地方!"<<endl;
    if(a==10)
        cout<<"* 马克思主义学院!"<<endl;
    if(a==11)
        cout<<"* 计算机科学与技术学院!"<<endl;
    if(a==12)
        cout<<"* 最古老的一栋楼,现用来办公!"<<endl;
    if(a==13)
        cout<<"* 数学院!"<<endl;
    if(a==14)
        cout<<"* 统计学院!"<<endl;
    if(a==15)
        cout<<"* 可以打乒乓球,排球,羽毛球,篮球……注意进门登记哦!"<<endl;
}
void Query1()
{
    int a,b,c;
    cout<<"======出行方式====="<<endl;
    cout<<"1.步行."<<endl;
    cout<<"2.驾车."<<endl;
    cout<<"================="<<endl;
    cout<<"输入你的选择(1 or 2):";
    cin>>a;
    cout<<"输入起点编号:";
    cin>>b;
    cout<<"输入终点编号:";
    cin>>c;
    if(b<=0&&b>=16||c<=0&&c>=16)
        cout<<"输入错误,景点不存在。"<<endl;
    else
        dijstra(b,a,c);
}
void DIS(int a,int b,int c)//计算dis数组
{
    memset(path,0,sizeof(path));
    int i,j,pos=1,minn,sum=0;
    memset(vis,0,sizeof(vis));
    for(i=1; i<=15; i++)
    {
        if(a==1)
            dis[i]=mapp[b][i];
        if(a==2)
            dis[i]=mapp1[b][i];
    }
    vis[b]=1;
    dis[b]=0;
    for(i=1; i<=15; i++)
    {
        minn=MAX;
        for(j=1; j<=15; j++)
        {
            if(vis[j]==0&&minn>dis[j])
            {
                minn=dis[j];
                pos=j;
            }
        }
        vis[pos]=1;
        for(j=1; j<=15; j++)
        {
            if(a==1)
            {
                if(vis[j]==0&&dis[j]>dis[pos]+mapp[pos][j])
                {
                    dis[j]=dis[pos]+mapp[pos][j];
                    path[j]=pos;
                }
            }
            if(a==2)
            {
                if(vis[j]==0&&dis[j]>dis[pos]+mapp1[pos][j])
                {
                    dis[j]=dis[pos]+mapp1[pos][j];
                    path[j]=pos;
                }
            }
        }
    }
}
void dijstra(int b,int a,int c)
{
    DIS(a,b,c);
    int x=c;
    while(!S.empty())
        S.pop();
//    for(i=1;i<=15;i++)
//        cout<<i<<" "<<path[i]<<endl;
//    cout<<endl;
    while(1)
    {
        if(x==0)
            break;
        S.push(x);
        x=path[x];
    }
    S.push(b);
    if(dis[c]>=100000)
        cout<<"没有直达的路,请选择步行。"<<endl;
    else
    {
        cout<<"从"<<b<<"到"<<c<<"的最短路径为:";
        while(!S.empty())
        {
            if(S.size()>1)
                cout<<S.top()<<"->";
            else
                cout<<S.top();
            S.pop();
        }
        cout<<endl<<"其最短距离为:"<<dis[c]<<endl;
    }

}
void DFS1(int b,int c)
{
    int i,j;
    vis[b] = 1;
    dq.push_back(b);
    for (j = 1; j <=15; j++)
    {
        if (j==c&&mapp[j][b]<=2000)
        {
            dd.push_back(dq);
            //return ;
        }
        if (vis[j]==0&&mapp[b][j]<=2000)
            DFS1(j,c);
    }
    vis[dq.back()] = 0;
    dq.pop_back();
}
void DFS2(int b,int c)
{
    int i,j;
    vis[b] = 1;
    dq.push_back(b);
    for (j = 1; j <=15; j++)
    {
        if (j==c&&mapp1[j][b]<=2000)
        {
            dd.push_back(dq);
//            return;
        }
        if (vis[j]==0&&mapp1[b][j]<=2000)
            DFS2(j,c);
    }
    vis[dq.back()] = 0;
    dq.pop_back();
}
void Query2()
{
    init();
    int a,b,c,i,j;
    cout<<"======出行方式====="<<endl;
    cout<<"    1.步行."<<endl;
    cout<<"    2.驾车."<<endl;
    cout<<"==================="<<endl;
    cout<<"输入你的选择(1 or 2):";
    cin>>a;
    cout<<"输入起点编号:";
    cin>>b;
    cout<<"输入终点编号:";
    cin>>c;
    // 队列 数组清零
    while(!dq.empty())
        dq.pop_front();
    while(!dd.empty())
        dd.pop_front();
    memset(vis,0,sizeof(vis));
    if(a==1)
        DFS1(b,c);
    else
        DFS2(b,c);
    if(dd.size()>=3)
    {
        cout<<"有三条以上(含3条),只输出前三条较短的路径:"<<endl;
        int p=0;
        for(i=1;; i++)
        {
            int g=dd.size();
            for(j=0; j<g; j++)
            {
                if(dd.front().size()==i)
                {
                    while(!dd.front().empty())
                    {
                        cout<<dd.front().front()<<" ";
                        dd.front().pop_front();
                    }
                    cout<<c<<endl;
                    p++;
                    if(p==3)
                        return;
                    dd.pop_front();
                    continue;
                }
                dd.push_back(dd.front());
                dd.pop_front();
            }
        }
    }
    else if(dd.size()!=0)
    {

        while(!dd.empty())
        {
            while(!dd.front().empty())
            {
                cout<<dd.front().front()<<" ";
                dd.front().pop_front();
            }
            cout<<c<<endl;
            dd.pop_front();
        }
    }
    else
        cout<<"没有直接相连的路径!!!"<<endl;

}
/*int Prim(int a,int x)
{
    init();
    int i,j,now;
    int sum=0;
    for(i=1; i<=15; i++)
    {
        dis[i]=MAX;
        vis[i]=0;
    }
    for(i=1; i<=15; i++)
    {
        if(a==1)
            dis[i]=mapp[x][i];
        else
            dis[i]=mapp1[x][i];
    }
    dis[x]=0;
    vis[x]=1;
    for(i=1; i<15; i++)
    {
        now=MAX;
        int min1=MAX;
        for(j=1; j<=15; j++)
        {
            if(vis[j]==0&&dis[j]<min1)
            {
                now=j;
                min1=dis[j];
            }
        }
        if(now==MAX)
            break;//防止不成图
        vis[now]=1;
        sum+=min1;
        if(a==1)
        {
            for(j=1; j<=15; j++)//添入新点后更新最小距离
            {
                if(vis[j]==0&&dis[j]>mapp1[now][j])
                {
                    dis[j]=mapp[now][j];
                    path[j]=now;
                }
            }
        }
        else
        {
            for(j=1; j<=15; j++)//添入新点后更新最小距离
            {
                if(vis[j]==0&&dis[j]>mapp1[now][j])
                {
                    dis[j]=mapp1[now][j];
                    path[j]=now;
                }
            }
        }
    }
}*/
void QQ(int a)
{
    int i,j,k,flag1=0;
    // 队列 数组清零
    while(!dq.empty())
        dq.pop_front();
    while(!dd.empty())
        dd.pop_front();
    memset(vis,0,sizeof(vis));
    //cout<<aa[e-1]<<"**"<<endl;
    if(a==1)
        DFS1(aa[0],aa[e-1]);
    else
        DFS2(aa[0],aa[e-1]);
    int n=dd.size();
    int yang=0;
    //DIS(a,aa[0],aa[e-1]);
    //cout<<" *****"<<n<<endl;
    for(k=1;k<=20; k++)
    {
        for(i=0; i<n; i++)
        {
            int m=dd.front().size();
            int sum=0;
            //cout<<"******"<<m<<endl;
            for(j=0; j<m; j++)
            {
                int hh=dd.front().front();
                if(flag[hh]==1)
                    sum++;
                dd.front().pop_front();
                dd.front().push_back(hh);
            }
            //cout<<"++++++"<<e-1<<endl;
            //cout<<"******"<<sum<<endl;
            if(sum>=e-1&&m==k)
            {
                flag1=1;
                yang++;
                if(yang==2)
                    return ;
                cout<<"路径为:";
                for(j=0;j<m;j++)
               // while(!dd.front().empty())
                {
                    cout<<dd.front().front()<<" ";
                    dd.front().push_back(dd.front().front());
                    dd.front().pop_front();
                }
                cout<<aa[e-1]<<" ";
                cout<<endl;
                //cout<<"其路径长度为:"<<dis[aa[e-1]]<<endl;

            }
            dd.push_back(dd.front());
            dd.pop_front();
        }

    }if(flag1==0)
            cout<<"**不存在这样的路径"<<endl;
}
void Query3()
{
    init();
    int a;
    memset(aa,0,sizeof(aa));
    memset(flag,0,sizeof(flag));
    cout<<"======出行方式====="<<endl;
    cout<<"    1.步行."<<endl;
    cout<<"    2.驾车."<<endl;
    cout<<"==================="<<endl;
    cout<<"输入你的选择(1 or 2):";
    cin>>a;
    cout<<"输入经过的点(以0结束,默认开始为起始点):";
    int b;
    while(1)
    {
        cin>>b;
        if(b==0)
            break;
        else
        {
            aa[e++]=b;
            flag[b]=1;
        }
    }
    aa[e]=0;
    // Prim(a,aa[0]);
    QQ(a);
}
void PP()
{
    cout<<"==================================山商平面图===================================="<<endl;
    cout<<"--------------------------------------------------------------------------------"<<endl;
    cout<<"|                             | 6.南门 |--------------------------------|      |"<<endl;
    cout<<"|        ...........              |   |                                 |      |"<<endl;
    cout<<"|        | 5.三餐 |---------------   ---------------------|             |      |"<<endl;
    cout<<"|        ```````````  |                                ---------        |      |"<<endl;
    cout<<"|        ...........  |                                |  8    |        |      |"<<endl;
    cout<<"|        | 4.二餐 |---                                 | 大活  |        |      |"<<endl;
    cout<<"|        ```````````  |           -----------          |       |        |      |"<<endl;
    cout<<"|                     |           |   7     |          ---------        |      |"<<endl;
    cout<<"|                     |-----------| 图书馆  |--------|      |           |      |"<<endl;
    cout<<"|    ..........       |           |         |        |      |         -------  |"<<endl;
    cout<<"| ---| 3.一餐 |-------|           -----------        |      |         |     |  |"<<endl;
    cout<<"| |  ``````````                                      |      |         |  9  |  |"<<endl;
    cout<<"| |       |-------                                   --------         |  办 |  |"<<endl;
    cout<<"| |              |   --------         ----------     | 10    |--------|  公 |  |"<<endl;
    cout<<"| |   ------     |  |  12   |         |   11    |----| 四教 |         |  楼 |  |"<<endl;
    cout<<"| |  |  2  |--------| 一教  |---------|  二教  |     --------         |     |  |"<<endl;
    cout<<"| |  | 操场|        --------          ----------           |          -------  |"<<endl;
    cout<<"| |   ------            |                                  |              |    |"<<endl;
    cout<<"|-----|----------------------------|-----------------------|--------------|    |"<<endl;
    cout<<"|  1  |    -----------  |      ----------              ----------              |"<<endl;
    cout<<"| 东门|----|  15     |--|      |   13    |             |   14   |              |"<<endl;
    cout<<"|-----|    |  体育馆 |         |  三教   |             |  五教  |              |"<<endl;
    cout<<"|          |         |         ----------              ----------              |"<<endl;
    cout<<"--------------------------------------------------------------------------------"<<endl;
}
void menu()
{
    int a;
    init();
    while(1)
    {
        cout<<"============菜单============"<<endl;
        cout<<"0.退出."<<endl;
        cout<<"1.查询所有景点信息."<<endl;
        cout<<"2.查询两景点的最短路径."<<endl;
        cout<<"3.查询两景点的所有路径."<<endl;
        cout<<"4.查询多景点的最佳路径."<<endl;
cout<<"5.山东工商学院平面图."<<endl;
        cout<<"==========================="<<endl;
        cout<<"输入你的选择(0 ~ 4):";
        cin>>a;
        if(a==0)
            break;
        if(a==1)
            Query();
        if(a==2)
            Query1();
        if(a==3)
            Query2();
        if(a==4)
            Query3();
        if(a==5)
            PP();
    }
}
int main()
{
    menu();
    return 0;
}

6 程序调试与测试

实现第一个功能:

实现第一个功能:

 

实现第二个功能:

 

实现第三个功能:

 

实现第四个功能:

 

7 结果分析

当输入2查询最短路径的时候,输出最短路径以及长度。

当输入3查询所有路径的时候,当有超过3条以上的道路时,输出3条经过景点最少的路径。

当输入4查询经过多点的最佳路径时,如果有路径,默认输出经过景点最少的一条路径。没有路径输出不存在。

每个都可以选择步行或者行车方式。

8 总结

总代码500多行,利用了最短路,DFS算法,写这个代码收获最多的就是学会了双重队列,就是在一个队列里面可以放多个队列。选择学校的15个景点,多条道路,区分了人行道和行车道。时间复杂度O(n*n),其中n是15,空间复杂度O(1)。代码花费时间为2天,呕心沥血之作,可能其中会有多多少少的错误,还需要进一步改进。我是用标号来代表地点的,输出也是用标号代替的,其实最完美的是输出要用真实的景点名称来代替,下次写代码之前一定先好好考虑,选好存储方式。这个课题是本次实训收获最大的一个课题。

参考文献

 [1] 刘晓华,唐焕玲.数据结构与算法(C语言版)[M].北京:清华大学出版社,2015

 

如有错误,欢迎指正。

  • 27
    点赞
  • 149
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值