校园导航、游览模式设计

  • 课题内容和要求
  • 课题需求分析
  • 相关数据结构及算法设计
    • 主要的数据结构
    • 主要算法流程
  • 源程序代码 (部分)
  • 测试数据及其结果

本课题采用C++语言,利用图形化工具Qt5.8.0设计,完整代码在 github上,请下载后查看。除代码外,github上的资源还包括:

  1. 含有可独立运行的exe可执行文件的Navigate文件夹
  2. 程序可能用到的原始数据

课题内容和要求

根据南京邮电大学仙林校区的校内主要建筑物和道路,构建一张带权无向图。完成校内导航模式设计和游览模式设计。具体要求如下:
(1)构建校内带权无向图,并用图形界面进行显示。
(2)导航模块设计:输入起始位置和终点位置,给出最优路线及两条备选路线。
(3)游览模式设计:构建算法,分析是否能设计遍览校内景点一次且仅一次的路线图和遍历校内所有路径一次且仅一次的路线图。

课题需求分析

本课题目标系统“校园导航、游览模式设计”的功能框架图如图1所示。

(1)支持选择起点和终点,并给出最短路径。
(2)给出两条备选路径,并用不同颜色显示;为方便区别,给出备选路径的时候清空推荐路径。
(3)设计一次游园模式,即从一个顶点出发,能遍历所有的点一次且仅一次。
(4)支持地图选点,查看详细信息,并设置为起点或终点。
(5)设计一次遍历所有路径一次且仅一次模式,若不能遍历完所有路径,则转到游园模式。

相关数据结构及算法设计

主要的数据结构

采用邻接表存储带权无向图的信息,数据结构如下:

typedef struct  ENode{int adjVex;//任意顶点u相邻接的顶点int w;//边的权值struct ENode* nextArc;//指向下一个边结点
}ENode;
typedef struct{int n;//图的当前顶点数int e;//图的当前边数ENode **a;//指向一维指针的数组
}LGraph;

主要算法流程

(1)路径规划算法:使用Dijkstra算法求最短路径,先初始化数组s,d,path,然后求最短路径,更新d和path并把顶点k加入s中,循环再求最短路径。其算法的流程图如下:

(2)备选路径算法:求备选路径时,先将Dijkstra算法求出的最短路径存入isChosen数组中,然后删除数组中权值最大的边,再用Dijkstra算法求最短路径,此时求得第一条备选路径。再从备选路径数组中删除权值最小的边,用Dijkstra算法求最短路径,此时求得第二条备选路径。
(3)设计一次游园路径:利用图的深度优先遍历,从一个顶点出发,调用递归算法,求能否经过所有的点一次且仅一次。其算法流程图如下:

(4)设计一次遍历所有的路:从某一结点出发,遍历所有的路一次且仅一次,即判断图是不是“欧拉(半)图”。对于连通图来说,如果结点没有奇数度节点,则其是欧拉图;若有两个奇数度节点,则其是欧拉半图。因此只要数奇数度节点即可判断能不能遍历所有的路一次且仅一次。
(5)路径展示算法:根据路径规划算法中求得的结点序列,在背景图上依次连接各个结点。
(6)地图选点:捕捉鼠标左键单击位置,判断其与图上点的位置关系,以此来区分不同的点。

源程序代码 (部分)

  1. map.h定义Dijkstra算法,用于求最短路径
void Dijkstra(int v);//dijkstra算法求最短路径

map.cpp实现如下:

void Map::Dijkstra(int v)
{ENode *q;if (v<0 || v>lg->n)return ;int *s = (int *)malloc(sizeof(int)*lg->n);int i;ENode *p;for (i = 0; i < lg->n; i++)                     //初始化{d[i] = INFTY;s[i] = 0;path[i] = -1;}p=lg->a[v];while (p)                                   //顶点v为源点{d[p->adjVex] = p->w;if (i != v && d[p->adjVex] < INFTY)path[p->adjVex] = v;p = p->nextArc;}s[v] = 1;d[v] = 0;int k;for (i = 1; i <= lg->n-1; i++){k = Choose(d, s, lg->n);s[k] = 1;                                 //k加入s中q = lg->a[k];while (q)                                   //更新d和path{if (s[q->adjVex] == 0 && d[k] + q->w < d[q->adjVex]){d[q->adjVex] = d[k] + q->w;path[q->adjVex] = k;}q = q->nextArc;}}free(s);
}

2)map.h定义SecondDijkstra算法,用于求备选路径

void SecondDijkstra(int u, int v);    //dijkstra算法求第二路径

map.cpp实现如下:

void Map::SecondDijkstra(int u,int v)//删除权值最大的边,重新求最短路径
{int k=0;ENode *p,*q;int t=0;int maxEdge=0;for(int i=0;i<lg->n;i++) {p=lg->a[i];while(p){if(maxEdge<=p->w&&isChosen[i][p->adjVex]==true&&OutEdge(i)>1&&OutEdge(p->adjVex)>1){maxEdge=p->w;k=i;t=p->adjVex;}p=p->nextArc;}}Remove(k,t);Remove(t,k);if (v<0 || v>lg->n)return;int *s = (int *)malloc(sizeof(int)*lg->n);int i;for (i = 0; i < lg->n; i++)                                 //初始化{Secondd[i] = INFTY;s[i] = 0;SecondPath[i] = -1;}p = lg->a[u];while (p)                                             //顶点u为源点{Secondd[p->adjVex] = p->w;if (i != u && Secondd[p->adjVex] < INFTY)SecondPath[p->adjVex] = u;p = p->nextArc;}s[u] = 1;Secondd[u] = 0;for (i = 1; i <= lg->n-1; i++){k = Choose(Secondd, s, lg->n);s[k] = 1;                                         //k加入s中q = lg->a[k];while (q)                                           //更新d和path{if (s[q->adjVex] == 0 && Secondd[k] + q->w < Secondd[q->adjVex]){Secondd[q->adjVex] = Secondd[k] + q->w;SecondPath[q->adjVex] = k;}q = q->nextArc;}}free(s);//选择矩阵归零,以备一下次选择for(int i=0;i<Max_Vex;i++)for(int j=0;j<Max_Vex;j++)isChosen[i][j]=false;
}

3)map.h定义欧拉(半)图的判断和输出:

int JudgeEulur();                 //判断欧拉图
void DFSEdge(int v);             //深度优先遍历边

map.cpp实现如下:

int Map::JudgeEulur()
{int count=0;for(int i=0;i<Max_Vex;i++){if(OutEdge(i)%2==1)   //数奇数度节点count++;}return count;
}void Map::DFSEdge(int v)
{DFSedgevisited.push_back(v);ENode*w;int q;for(w=lg->a[v];w;w=w->nextArc){q=w->adjVex;if(Exist(v,q)){Remove(v,q);Remove(q,v);DFSEdge(q);}}
}

4)mainwindow.h定义FindPath()函数,用于找到最短路径并在地图上画出来。

void FindPath();   //用于寻找最短路径并在图上显示,响应开始导航按钮和切换路线按钮

mainwindow.cpp实现如下:

void MainWindow::FindPath()
{page=0;Clear();AddEdge();QPainter paint(&paintMap->map);m->Dijkstra(StartComboBox->currentIndex());QVector<int> nextPath;nextPath=get_Path(EndComboBox->currentIndex());paint.setBrush(Qt::red);paint.drawEllipse(paintMap->qpointF[nextPath[0]]-QPointF(50,150),5,5);paint.setBrush(Qt::blue);paint.drawEllipse(paintMap->qpointF[nextPath[nextPath.size()-1]]-QPointF(50,150),5,5);QPen pen;pen.setWidth(3);pen.setColor(QColor(50,205,50));paint.setPen(pen);for(int i=1;i<nextPath.size();i++){qDebug()<<nextPath[i]<<",";m->setIsChosen(nextPath[i-1],nextPath[i],true);}//开始画路径QPainterPath path;path.moveTo(StartPos.x()-50,StartPos.y()-150);for(int i=1;i<nextPath.size();i++){path.lineTo(paintMap->qpointF[nextPath[i]].x()-50,paintMap->qpointF[nextPath[i]].y()-150);paint.drawPath(path);path.moveTo(paintMap->qpointF[nextPath[i]].x()-50,paintMap->qpointF[nextPath[i]].y()-150);}this->update();          //调用PaintEvent重画事件page++;
}

5)mainwindow.h定义函数PaintEvent

void paintEvent(QPaintEvent *);//重画事件

mainwindow.cpp重新实现此虚函数如下:

void MainWindow::paintEvent(QPaintEvent *event)
{QPainter paint(this);paintMap->drawBackground(&paint);//画背景地图//画图例paint.setBrush(Qt::red);paint.drawEllipse(QPointF(625,55),5,5);paint.drawText(QPointF(635,60),tr("起点"));paint.setBrush(Qt::blue);paint.drawEllipse(QPointF(625,75),5,5);paint.drawText(QPointF(635,80),tr("终点"));QPen pen;pen.setWidth(3.5);pen.setColor(QColor(50,205,50));paint.setPen(pen);paint.drawLine(QPointF(600,95),QPointF(625,95));pen.setColor(Qt::black);paint.setPen(pen);paint.drawText(QPointF(635,100),tr("推荐路线"));pen.setWidth(3.5);pen.setColor(QColor(173,255,47));paint.setPen(pen);paint.drawLine(QPointF(600,115),QPointF(625,115));pen.setColor(Qt::black);paint.setPen(pen);paint.drawText(QPointF(635,120),tr("备选路线1"));pen.setWidth(3.5);pen.setColor(QColor(144,238,144));paint.setPen(pen);paint.drawLine(QPointF(600,135),QPointF(625,135));pen.setColor(Qt::black);paint.setPen(pen);paint.drawText(QPointF(635,140),tr("备选路线2"));
}

6)mainwindow.cpp构造函数中,实现关联切换路径与函数的代码如下:

connect(ReverseButton,&QPushButton::released,[=]()mutable{if(page%3==1){emit FindSecondPath();page++;}else if(page%3==2){emit FindThirdPath();page++;}else{emit FindPath();}});

程序所有的源代码已上传github:
https://github.com/FFtu-ChrisKun/Navigate_in_NJUPT

测试数据及其结果

1)测试导航模块:
测试用例1:起点:南门 终点:北门
测试用例2:起点:教2 终点:桂苑
测试结果:


2) 测试地图选点:
测试用例:起点:青教 终点:南一
测试结果:

3)测试切换路线:
测试用例:起点:青教 终点:南一
测试结果:


4)测试我要游园:
测试结果:


5)测试我想走路:
测试结果:

校园导航-南邮仙林校区相关推荐

  1. [Depricated]适用coremail邮件系统,第三方客户端绑定校园邮箱(南邮、河海,以iOS邮件为例)

    本文已作废,南京邮电大学已于 2022-1 正式启用腾讯企业邮箱服务,不再使用 coremail,腾讯企业邮箱的设置在邮箱设置界面有清楚说明. 校内师生之间联系常基于校内邮件系统,而网页版的邮件系统对 ...

  2. 南邮的计算机学院地址,南京邮电大学校区有几个 地址是什么

    为了让各位读者更好的了解南京邮电大学,小编在这里整理了南京邮电大学的校区及地址,希望能对各位读者有所帮助. 南京邮电大学的校区及地址 南京邮电大学有四个校区,分别是仙林校区.三牌楼校区.锁金村校区.江 ...

  3. “Wishare杯”南邮第八届大学生程序设计竞赛之现场决赛 题解报告

    A.爆炸吧,现充 (红) 时间限制:1000ms           内存限制:65536K 题目描述: a协有部分脱团分子,日复一日,年复一年地进行秀恩爱虐狗行为,对其他成员持续造成着精神伤害.Ko ...

  4. 研究生计算机学院换研究方向不换导师,南邮自杀研究生曾抱怨“导师不让毕业” 导师被停职...

    1月25日上午9点,南京市新模范马路66号,南京邮电大学综合科研大楼,计算机学院研三的学生蒋华文从9楼一坠而下,结束了自己25岁的生命. 澎湃新闻(www.thepaper.cn)采访获悉,就在自杀前 ...

  5. 南邮计算机学院哪个研究生导师项目比较多,南邮自杀研究生曾抱怨“导师不让毕业” 导师被停职...

    1月25日上午9点,南京市新模范马路66号,南京邮电大学综合科研大楼,计算机学院研三的学生蒋华文从9楼一坠而下,结束了自己25岁的生命. 澎湃新闻(www.thepaper.cn)采访获悉,就在自杀前 ...

  6. 南邮计算机专业考什么,南京邮电大学计算机考情分析与经验分享

    原标题:南京邮电大学计算机考情分析与经验分享 一.南邮及南邮计算机 南京邮电大学,简称"南邮",是教育部.工业和信息化部.国家邮政局与江苏省共建高校.是双一流学校,虽然不是211/ ...

  7. 妈妈,我以后也要上南邮!

    我一上车发现角落里只有一个空位了,旁边坐着一个mm,嘿嘿,我忙走过去一屁股坐下,那漂亮mm很熟练的皱皱眉头,职业性的使劲往旁边挪. "到 哪?" "南邮." & ...

  8. 南邮 OJ 1484 烧饼重叠问题

    烧饼重叠问题 时间限制(普通/Java) : 1000 MS/ 3000 MS          运行内存限制 : 65536 KByte 总提交 : 87            测试通过 : 12 ...

  9. 再见,南邮!别了,南京!

    "光阴似箭,日月如梭",又一个三年就这样匆匆地过去了.回望过去三年我在南邮的学习生活,所有的快乐.所取得的成绩以及曾经经历过的困难与挫折,所有的这一切都如同一部电影一样在我的脑海里 ...

最新文章

  1. Python,OpenCV提取图片中的多个茄子种子轮廓,并按从左到右排序后显示
  2. SQL Server-聚焦SNAPSHOT基于行版本隔离级别详解(三十)
  3. ACS AD 和本地验证SSL ×××
  4. win10中cmd如何编译和运行c/c++程序?
  5. 正则化与L0、L1、L2范数祥解
  6. android IntentService
  7. 2017.3.23下午
  8. 网易云课堂测试微专业前置课
  9. zbbz的lisp_学习LISP语言的体会
  10. 当驾校学员遇上微信小程序
  11. 学习Linux的第七十一天
  12. 你的 Mac 用对了吗?推荐一些 Mac 上比较好用的软件
  13. 有一个已经排好序的数组,要求输入一个数后,按原来排序的规律将它插入数组中
  14. 彻底删除2345输入法
  15. 科大讯飞刘庆峰:AI要改变世界,算法、大数据、行业专家缺一不可
  16. 目标跟踪CLE绘图 OTB数据跟踪绘图 mat文件txt文件 相互转换
  17. 经典古诗词名句 mysql,中国古代经典古诗词名句
  18. 不可忽视的UPS电源电池除尘
  19. 基于DPABI和SPM12的任务态fMRI分析笔记1——预处理
  20. oracle 开启utl_tcp,关于Oracle的UTL_TCP

热门文章

  1. IDEA 注释字体设置
  2. 通过GRUB2打造多系统混合安装U盘
  3. 高等数学——转动惯量
  4. JMS与Spring
  5. 找个搞IOS逆向的大佬写个越狱插件,接单的联系,APP没加密,有可参照,有接单的大佬请联系下
  6. zabbix使用宏自动发现网卡并实现监控(入职小灰)
  7. JMeter | 监控服务器性能
  8. 《安富莱嵌入式周报》第284期:Matlab2022b发布,支持从 .NET 调用,耳机放大器,牛屎芯片替换,JSON可视化,开源的飞行软件和嵌入式系统框架
  9. SD卡损坏了怎么办?sd卡恢复,80%的用户都试过这些方法
  10. C语言 实现n*n的方阵,循环右移m位