校园导航问题-HBU DS 大作业
~
~
看到大佬有用QT写的,真的惊艳到了呀。
问题描述
以我校为例,设计一个校园导航系统,主要为来访的客人提供信息查询。系统有两类登陆账号,一类是游客,使用该系统方便校内路线查询;一类是管理员,可以使用该系统查询校内路线,可对校园景点路线可编辑。
需求分析
设计学校的平面图,至少包括10个以上景点(场所),每两个景点间可以有不同道路,且路长也可能不同,找出在游人所在景点到其他景点的最短路径,或游人输入的任意两个景点的最短路径。 要求: (1) 以图中顶点表示校园内各景点,存放景点名称、代号、简介等信息;以边表示路径,路径权重为路径长度。 (2) 为游人提供任意景点相关信息查询。 (3)为游人提供任意景点的问路查询,即任意两个景点之间的最短路径。
主要功能
主要功能模块 (1)创建图的邻接矩阵存储结构 create() (2) 浏览图中任一景点介绍 (3) 修改景点信息 (4) 增加景点信息 (5) 删除景点信息 (6) 增加道路 (7) 删除道路 (8) 查找某一景点到其他景点的最短路径
(9) 查找任一两个景点之间的最短路径。 3 主模块流程 管理员登陆,可实现(1)-(9)功能操作 游客登陆,在(1)基础实现基础之上,可实现 (2)(8)(9)功能操作
代码_有亿点点乱
/*
时间线: 2020 12 02 晚
项目开始
创建数据结构
发现bug :用malloc给string申请空间(其实vector也不行) 找了 好几个小时bug!!!
2020 12 03 实验课
bug:如果循环cin>>int>>string 如果输入的是int string string 那将直接结束所有输入
实现 操作 1 函数:CreatGraph
操作2 函数 PrintSpotsInfo 打印的是所有的景点
操作8 写了一点点点
2020 12 03 下午
bug:最小路径有问题 原因:邻接矩阵没有路径的值为0
解决方案:创建图的时候把邻接矩阵的边都初始化最大
实现 操作8 9
********
//中间 没记录
2020 12 10 晚
bug 1.G->v_num设置的初始值为11 应该为12 导致一直就输出了11 个点
bug 2.admin && visitor 公用着几个函数,每次返回的时候只返回到管理员界面
解决: 在那几个公用函数参数里加入 bool 变量,如果true 返回管理员面板 false 返回游客面板
3.没有做容错处理 让输入景点对应的坐标op 如果op-1 不在数组的有效范围之内就会 程序崩溃
解决:在每个输入 加入容错处理 会判断输入是否合法 不合法一直让用户重新输入
完成
*/
#include <cstdio>
#include <string>
#include <windows.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <iostream>
using namespace std;
#define MaxVNodeNum 20
#define INF 2147483647 // int 可以表示的最大值
struct VexNode
{
int num;
string name;
string features;
};
typedef struct GraphNode *Graph;
struct GraphNode
{
VexNode vexs[MaxVNodeNum];
int Edge[MaxVNodeNum][MaxVNodeNum];
int v_num, e_num;
//enum 为关键词
};
string AdminId = "hbu";
string Password = "hbu";
string SOMESPACE = "\t\t\t\t\t";
Graph G = new GraphNode();
void Init(); // 进入界面
void AdminLoginUi(); //管理员登录界面
void AdminUi(); //管理员界面
void VisitUi(); //游客界面
int CreatGraph(); //创建图
int PrintVexAndName(); //打印 各个景点在程序内部储存的编号
void PrintSpotsInfo(int i, bool flag); //打印景点信息 1是打印全部 0是打印一个 bool true admin false visit
void FindShortestPath_Dijkstra(int vm, int target, bool flag);
void AddSpots(); //增加结点信息
void ChangeSpotsInfo();
void DelSpots();
void AddPath();
void DelPath();
//vm 是源点 target是要求的目的地 都是数组的下标
void FindShortestPath(int op, bool flag);
int main()
{
Init();
}
void Init() //初始化函数,显示 进入系统
{
system("cls");
CreatGraph();
system("color f0"); //cmd颜色亮白色 黑色
int i;
printf("\n\n\n\t\t\t\t\t正在进入河北大学导航系统\n\n\n");
for (i = 0; i < 120; i++)
{
if (i % 2)
printf("%c", '*');
else
printf("%c", ' ');
Sleep(5);
}
printf("如果您是管理员请按1,游客请按2!\n");
string op;
cin >> op;
while (1)
{
if (op == "1" || op == "2")
break;
printf("操作有误!重新输入!\n");
cin >> op;
}
if (op == "1")
AdminLoginUi();
else if (op == "2")
VisitUi();
}
void VisitUi() //游客界面
{
time_t timep;
struct tm *p;
time(&timep);
p = gmtime(&timep);
/*获取当前月份日数,范围是1-31.获取当前月份,范围是0-11,所以要加1获取当前年份,从1900开始,所以要加1900*/
int y0 = 1900 + p->tm_year, m0 = 1 + p->tm_mon, d0 = p->tm_mday;
char c;
do
{
system("cls");
printf("\n\n\n\n\n\n\t\t\t\t 今天是%d年%02d月%02d日!大家学习快乐!\n\n\n", y0, m0, d0);
printf("\t\t\t\t ╭═════════════════════════════════════════════╮\n");
printf("\t\t\t\t │ 河北大学导航系统-HBUCompass │\n");
printf("\t\t\t\t ╰═════════════════════════════════════════════╯\n");
printf("\t\t\t\t ┌───────────────────────────────────────────────────┐\n");
printf("\t\t\t\t │ │\n");
printf("\t\t\t\t │ 1. 浏览图中任一景点介绍 2. 浏览所有景点信息 │\n");
printf("\t\t\t\t │ │\n");
printf("\t\t\t\t │ 3.查找一景点到其他景点的最短距离 │\n");
printf("\t\t\t\t │ │\n");
printf("\t\t\t\t │ 4.查找任两个景点间的最短距离 │\n");
printf("\t\t\t\t │ │\n");
printf("\t\t\t\t │ Esc. 退出程序 │\n");
printf("\t\t\t\t └───────────────────────────────────────────────────┘\n");
printf("\t\t\t\t\t\t 请您选择(1-4):");
c = getche();
} while (!(c > '0' && c <= '9' || c == 0x1b));
if (c == 0x1b)
_exit(0);
else if (c == '1')
PrintSpotsInfo(0, false);
else if (c == '2')
PrintSpotsInfo(1, false);
else if (c == '3')
FindShortestPath(1, false);
else if (c == '4')
FindShortestPath(2, false);
}
void AdminLoginUi() //管理员登录界面
{
while (1)
{
cout << SOMESPACE;
printf("如果你是管理员,请输出您的账号!\n");
string curid, curpassword;
cout << SOMESPACE;
cin >> curid;
cout << SOMESPACE;
printf("请输出你的密码!\n");
cout << SOMESPACE;
cin >> curpassword;
if (curid == AdminId && curpassword == Password)
break;
}
cout << SOMESPACE;
printf("您已登录,欢迎管理员回来!\n");
AdminUi();
}
void AdminUi()
{
time_t timep;
struct tm *p;
time(&timep);
p = gmtime(&timep);
/*获取当前月份日数,范围是1-31.获取当前月份,范围是0-11,所以要加1获取当前年份,从1900开始,所以要加1900*/
int y0 = 1900 + p->tm_year, m0 = 1 + p->tm_mon, d0 = p->tm_mday;
char c;
do
{
system("cls");
printf("\n\n\n\n\n\t\t\t\t\t今天是%d年%02d月%02d日!大家学习快乐,学习辛苦!!\n\n\n", y0, m0, d0);
printf("\t\t\t\t ╭═════════════════════════════════════════════╮\n");
printf("\t\t\t\t │ 河北大学导航系统-HBUCompass │\n");
printf("\t\t\t\t ╰═════════════════════════════════════════════╯\n");
printf("\t\t\t\t ┌───────────────────────────────────────────────────┐\n");
printf("\t\t\t\t │ │\n");
printf("\t\t\t\t │ 1. 浏览图中任一景点介绍 2. 浏览所有景点信息 │\n");
printf("\t\t\t\t │ │\n");
printf("\t\t\t\t │ 3. 修改景点信息 4. 增加景点 │\n");
printf("\t\t\t\t │ │\n");
printf("\t\t\t\t │ 5.删除景点 6.增加道路 │\n");
printf("\t\t\t\t │ │\n");
printf("\t\t\t\t │ 7.删除道路 8.查找一景点到其他景点的最短距离 │\n");
printf("\t\t\t\t │ │\n");
printf("\t\t\t\t │ 9.查找任两个景点间的最短距离 Esc. 退出程序 │\n");
printf("\t\t\t\t └───────────────────────────────────────────────────┘\n");
printf("\t\t\t\t\t\t 请您选择(1-9):");
c = getche();
} while (!(c > '0' && c <= '9' || c == 0x1b));
system("cls");
if (c == 0x1b)
_exit(0);
else if (c == '1')
PrintSpotsInfo(0, true);
else if (c == '2')
PrintSpotsInfo(1, true);
else if (c == '3')
ChangeSpotsInfo();
else if (c == '4')
AddSpots();
else if (c == '5')
DelSpots();
else if (c == '6')
AddPath();
else if (c == '7')
DelPath();
else if (c == '8')
FindShortestPath(1, true);
else if (c == '9')
FindShortestPath(2, true);
}
int PrintVexAndName() //打印 各个景点储存的编号
{
for (int i = 0; i < G->v_num; ++i)
cout << G->vexs[i].name << "->" << G->vexs[i].num << endl;
}
void PrintSpotsInfo(int i, bool flag) //打印景点信息 i 1 打印全部 0 打印部分
{
system("cls");
if (i == 1)
{
printf("这是河北大学的景点信息!\n");
for (int i = 0; i < G->v_num; ++i)
{
auto &x = G->vexs[i];
printf("编号:%2d 名称%16s 介绍:%20s\n", x.num, x.name.c_str(), x.features.c_str());
}
printf("\n\t\t\t\t\t 按下esc退出 其余任意键返回主界面!");
char react = getche();
if (react == 0x1b)
_exit(0);
else
{
if (flag)
AdminUi();
else
VisitUi();
}
}
else
{
PrintVexAndName();
cout << endl
<< SOMESPACE;
cout << "请输入你想查看的景点信息对应的编号\n";
int op;
cin >> op;
while (1)
{
if (op >= 1 && op <= G->v_num)
break;
printf("您输入的数据不合法,请重新输入!\n");
cout << SOMESPACE;
cin >> op;
}
auto &x = G->vexs[op - 1];
printf("编号:%3d 名称:%10s 介绍:%20s\n", x.num, x.name.c_str(), x.features.c_str());
printf("\n\n\n\t\t\t\t\t 按下esc退出 按下空格重新查看另外景点信息 其余任意键返回主界面!");
char react = getche();
if (react == 0x1b)
_exit(0);
else if (react == ' ')
PrintSpotsInfo(0, flag);
else
{
if (flag)
AdminUi();
else
VisitUi();
}
}
}
void FindShortestPath(int op, bool flag)
{
system("cls");
PrintVexAndName();
if (op == 1)
{
printf("\n\t\t\t\t\t请输入你想查看哪个景点到其他所有景点的最短距离");
int op1;
cin >> op1;
FindShortestPath_Dijkstra(op1 - 1, -1, flag); // 函数接收的是数组下标
}
else
{
printf("\n\t\t\t\t\t请输入你想查看哪两个景点间的最短距离");
int op1, op2;
cin >> op1 >> op2;
while (1)
{
if (op1 >= 1 && op1 <= G->v_num && op2 >= 1 && op2 <= G->v_num)
break;
printf("\n\t\t\t\t\t你的输入有误!请重新输入!\n\t\t\t\t\t");
cin >> op1 >> op2;
}
FindShortestPath_Dijkstra(op1 - 1, op2 - 1, flag);
}
}
void FindShortestPath_Dijkstra(int vm, int target, bool flag)
{
double D[MaxVNodeNum];
int P[MaxVNodeNum];
int final[MaxVNodeNum] = {0};
for (int i = 0; i < G->v_num; ++i)
{
if (G->Edge[vm][i])
D[i] = G->Edge[vm][i];
else
D[i] = INF;
P[i] = vm;
}
P[vm] = -1;
final[vm] = 1;
D[vm] = 0;
for (int i = 1; i < G->v_num; ++i) //做n-1次循环
{
int min = INF;
int idx = -1;
for (int j = 0; j < G->v_num; ++j)
{
if (final[j] == 0 && D[j] < min) //S集合中的
{
min = D[j];
idx = j;
}
}
//idx 是最小那个点
final[idx] = 1;
for (int j = 0; j < G->v_num; ++j)
{
if (final[j] == 0 && D[idx] + G->Edge[idx][j] < D[j]) //s
{
D[j] = D[idx] + G->Edge[idx][j];
P[j] = idx;
}
}
}
//输出
if (target == -1)
{
for (int i = 0; i < G->v_num; ++i)
{
if (i != vm)
{
int sum = 0;
int pos = P[i];
sum += G->Edge[i][pos];
printf("%s", G->vexs[i].name.c_str());
while (pos >= 0)
{
if (P[pos] >= 0)
sum += G->Edge[pos][P[pos]];
printf("<-%s", G->vexs[pos].name.c_str());
pos = P[pos];
}
cout << " 最短路径长度:" << sum << endl;
}
}
printf("\n\t\t\t\t\t 按下esc退出 按下空格重新查询 其余任意键返回主界面!");
char react = getche();
if (react == 0x1b)
_exit(0);
else if (react == ' ')
FindShortestPath(1, flag);
else
{
if (flag)
AdminUi();
else
VisitUi();
}
}
else
{
int sum = 0;
int pos = P[target];
sum += G->Edge[target][pos];
printf("%s", G->vexs[target].name.c_str());
while (pos >= 0)
{
if (P[pos] >= 0)
sum += G->Edge[pos][P[pos]];
printf("<-%s", G->vexs[pos].name.c_str());
pos = P[pos];
}
cout << " 最短路径长度:" << sum << endl;
printf("\n\t\t\t\t\t 按下esc退出 按下空格重新查询 其余任意键返回主界面!");
char react = getche();
if (react == 0x1b)
_exit(0);
else if (react == ' ')
FindShortestPath(2, flag);
else
{
if (flag)
AdminUi();
else
VisitUi();
}
}
}
void ChangeSpotsInfo()
{
system("cls");
PrintVexAndName();
printf("请输入你想改变的景点对应的数字!\n");
int op;
cin >> op;
while (1)
{
if (op >= 1 && op <= G->v_num)
break;
printf("\n\t\t\t\t\t你输入不合法,请重新输入!\n\t\t\t\t\t");
}
printf("请输出你更改后的名称 介绍!\n");
cin >> G->vexs[op - 1].name >> G->vexs[op - 1].features;
printf("\n\n\n\t\t\t\t\t 按下esc退出 按下改变景点信息 其余任意键返回主界面!");
char react = getche();
if (react == 0x1b)
_exit(0);
else if (react == ' ')
ChangeSpotsInfo();
else
AdminUi();
}
int CreatGraph()
{
G->v_num = 12;
for (int i = 0; i < G->v_num; ++i)
G->vexs[i].num = i + 1;
G->vexs[0].name = "图书馆";
G->vexs[0].features = "冬暖夏凉,学习睡觉(小憩)不二之选!";
G->vexs[1].name = "操场";
G->vexs[1].features = "运动的好地方,正在盖游泳馆";
G->vexs[2].name = "体检中心";
G->vexs[2].features = "体检中心";
G->vexs[3].name = "邯郸音乐厅";
G->vexs[3].features = "听音乐的地方";
G->vexs[4].name = "花园景观";
G->vexs[4].features = "一个很美丽的地方";
G->vexs[5].name = "校园北口";
G->vexs[5].features = "疫情之后,连接了教学区和生活区";
G->vexs[6].name = "银杏景观";
G->vexs[6].features = "景观大道!";
G->vexs[7].name = "餐厅";
G->vexs[7].features = "干饭的好地方,但是经常不知道吃啥";
G->vexs[8].name = "校园东口";
G->vexs[8].features = "疫情之后,联系了HBU和现实世界";
G->vexs[9].name = "信息学部";
G->vexs[9].features = "好像没有去过";
G->vexs[10].name = "网计学院";
G->vexs[10].features = "我们的学院!emm,希望再给点空间,老师说还有实验室要建。不如把D楼全弄成实验室(doge)";
G->vexs[11].name = "校园南口";
G->vexs[11].features = "基本没走过这个门,好像就去年偶尔走一下!";
G->Edge[0][8] = 300;
G->Edge[0][1] = 280;
G->Edge[0][3] = 400;
G->Edge[0][4] = 160;
G->Edge[1][2] = 350;
G->Edge[1][3] = 480;
G->Edge[1][5] = 200;
G->Edge[5][6] = 100;
G->Edge[5][7] = 100;
G->Edge[6][7] = 100;
G->Edge[7][8] = 100;
G->Edge[8][4] = 200;
G->Edge[8][11] = 600;
G->Edge[4][11] = 500;
G->Edge[4][9] = 150;
G->Edge[9][11] = 400;
G->Edge[10][11] = 400;
G->Edge[10][3] = 500;
G->Edge[2][3] = 200;
G->Edge[3][9] = 500;
for (int i = 0; i < G->v_num; ++i)
for (int j = 0; j < G->v_num; ++j)
{
if (G->Edge[i][j])
G->Edge[j][i] = G->Edge[i][j];
}
for (int i = 0; i < G->v_num; ++i)
for (int j = 0; j < G->v_num; ++j)
{
if (!G->Edge[i][j])
G->Edge[j][i] = G->Edge[i][j] = INF;
}
}
void DelSpots()
{
system("cls");
PrintVexAndName();
printf("\n\t\t\t\t\t请输入你想要删除的景点对应的编号!\n");
int op;
cin >> op;
while (1)
{
if (op >= 1 && op <= G->v_num)
break;
printf("\n\t\t\t\t\t你的输入有误,请重新输入!");
printf("\n\t\t\t\t\t");
cin >> op;
}
for (int i = op; i < G->v_num; ++i) //向左移
for (int j = 0; j < G->v_num; ++j)
G->Edge[j][i - 1] = G->Edge[j][i];
for (int i = op; i < G->v_num; ++i) //向上移
for (int j = 0; j < G->v_num; ++j)
G->Edge[i - 1][j] = G->Edge[i][j];
VexNode s = G->vexs[op - 1];
for (int i = op; i < G->v_num; ++i)
{
G->vexs[i - 1] = G->vexs[i];
}
G->v_num--;
printf("\n\t\t\t\t\t已删除完毕!\n\t\t\t\t\t名称:%s,介绍:%s", s.name.c_str(), s.features.c_str());
for (int i = op - 1; i < G->v_num; ++i)
G->vexs[i].num = i + 1;
printf("\n\n\n\t\t\t\t\t 按下esc退出 按下空格继续删除景点 其余任意键返回主界面!");
char react = getche();
if (react == 0x1b)
_exit(0);
else if (react == ' ')
DelSpots();
else
AdminUi();
}
void AddSpots()
{
system("cls");
if (G->v_num >= MaxVNodeNum)
{
printf("顶点已达上限,不能添加顶点\n");
return;
}
printf("请输入景点名称,介绍\n");
printf("\n请输入名称:\t");
cin >> G->vexs[G->v_num].name;
printf("请输入介绍:\t");
cin >> G->vexs[G->v_num].features;
G->vexs[G->v_num].num = G->v_num + 1;
G->v_num++;
printf("已经添加景点\n");
auto &x = G->vexs[G->v_num - 1];
printf("编号:%2d 名称%16s 介绍:%20s\n", x.num, x.name.c_str(), x.features.c_str());
printf("\n\n\n\t\t\t\t\t 按下esc退出 按下空格继续添加景点 其余任意键返回主界面!");
char react = getche();
if (react == 0x1b)
_exit(0);
else if (react == ' ')
AddSpots();
else
AdminUi();
}
void AddPath()
{
system("cls");
PrintVexAndName(); //打印 各个景点储存的编号
cout << endl
<< SOMESPACE;
printf("请输入你想添加的路径的两端以及长度,例如 1 2 100这种形式!\n");
int a, b, d;
cout << SOMESPACE;
cin >> a >> b >> d;
while (1)
{
if (a > 0 && b > 0 && a <= G->v_num && b <= G->v_num && a != b)
break;
printf("您输入的数据不合法,请重新输入!\n");
cout << SOMESPACE;
cin >> a >> b >> d;
}
G->Edge[a - 1][b - 1] = G->Edge[b - 1][a - 1] = d;
printf("已经添加路径! %s %s 距离:%d\n", G->vexs[a - 1].name.c_str(), G->vexs[b - 1].name.c_str(), d);
printf("\n\n\n\t\t\t\t\t 按下esc退出 按下空格继续添加路径 其余任意键返回主界面!");
char react = getche();
if (react == 0x1b)
_exit(0);
else if (react == ' ')
AddPath();
else
AdminUi();
}
void DelPath()
{
system("cls");
PrintVexAndName(); //打印 各个景点储存的编号
cout << endl
<< SOMESPACE;
printf("请输入你想删除的路径的两端,例如 1 2 \n");
int a, b;
cout << SOMESPACE;
cin >> a >> b;
while (1)
{
if (a > 0 && b > 0 && a <= G->v_num && b <= G->v_num && a != b)
break;
printf("您输入的数据不合法,请重新输入!\n");
cout << SOMESPACE;
cin >> a >> b;
}
G->Edge[a - 1][b - 1] = G->Edge[b - 1][a - 1] = INF;
printf("已经删除路径!\n");
printf("\n\n\n\t\t\t\t\t 按下esc退出 按下空格继续删除路径 其余任意键返回主界面!");
char react = getche();
if (react == 0x1b)
_exit(0);
else if (react == ' ')
DelPath();
else
AdminUi();
}