1.任务:设计一个城市交通咨询模拟系统,利用该系统实现至少两种最优决策:最短路程到达、最省时到达等线路规划。
2.内容:
用户驾车出行由于出行目的的不同对道路路线选择的要求也有不同。例如,有的希望在途中的路程尽可能短,有的则可能希望路程中时间最短。为了能满足广大旅客的需求,编制一个城市交通咨询模拟系统,选取城市部分位置、道路抽象为程序所需要图的顶点和边,并以城市道路长度(路程),道路的某时段的速度等信息作为图结点中的弧信息,为旅客提供这两种最优决策的交通咨询。

1、主要数据类型与变量

1.1 顶点,边,图的存储结构,还有宏定义,定点最大数,和无穷大

#define MAX_VERTEX_NUM 9  //顶点最大个数
#define INF 999 //代表无穷大
typedef struct {int no; //顶点编号char info; //顶点信息
}VertexType; //顶点类型
typedef struct GNode *PtrToGNode;typedef struct GNode{double edges[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//领接矩阵的定义int n,e;//顶点数和边数VertexType vex[MAX_VERTEX_NUM];//存放定点的信息
}Mgraph;
typedef PtrToGNode MGraph;typedef struct ENode *PtrToENode;
struct ENode {int V1, V2; /* 有向边<V1, V2> */double Weight; /* 权重km */int speed;/* 速度km/h */
};
typedef PtrToENode Edge;
1.2静态全局成员(目的:调用和修改方便)
dist数组,存放最短路径
static double dist[MAX_VERTEX_NUM];
Path数组,存放每个节点的前驱节点
static int path[MAX_VERTEX_NUM];
存放速度的二维数组,方便图中对应的坐标能找到对应的速度
static int speed[MAX_VERTEX_NUM][MAX_VERTEX_NUM];1.3函数结构说明
typedef PtrToENode Edge;
/*** 迪杰特斯拉最短路径算法* @param g 领接矩阵的图* @param v 起始顶点* @param dist 存放V到每个节点的最短路径的数组* @param path 存放每个节点的前驱节点*/
void Dijkstra(Mgraph g,int v,double dist[],int path[]);
/*** 目的是通过键盘输入创建图* @return*/
MGraph BuildGraph();
/*** 通过输入的顶点数初始化图,方便BuildGraph函数调用* @param VertexNum 顶点数* @return 返回初始化成功的图*/
MGraph CreateGraph( int VertexNum );
/*** 打印dist和path两个数组*/
void printMap();
/*** 目的是在边图中增加速度的数据* @param g 原来没有速度的图* @param speed 跟图一样的数组,但是对应的坐标存放的是速度*/
void addSpeed(Mgraph *g,int speed[][MAX_VERTEX_NUM]);
/*** 把最后关键的数据,返回到文件中,然后通过数据展示构建图在前端页面上* @param path 存放的路径* @param data 存放的数据*/
void writeFile(string path,string data);2、算法或程序模块
2.1 程序流程解释:
①创建图(领接矩阵):通过输入顶点数,边数,每条边的起点终点,每条边对应的速度,通过BuildGraph函数构造出来。
②通过迪杰特斯拉算法求出最短路径,将dist和path数组的数据记录一下,然后增加二维数组speed存放图的每个坐标所对应的速度,在通过T=S/V的公式计算出每条边所需要的时间(代替原来的路程),然后再使用一次迪杰特斯拉算法求出最短时间。
③输出两次记录的dist和path数组到前端页面,通过前端和数据构建出图的样式,最短路径和最短时间为红色,否则为绿色。
核心函数解释
typedef int Vertex; /* 用顶点下标表示顶点,为整型 */
MGraph CreateGraph( int VertexNum )
{ Vertex V, W;MGraph Graph;Graph = (MGraph )malloc(sizeof(MGraph));Graph->n = VertexNum;Graph->e = 0;
/* 注意:这里默认顶点编号从0开始,到(Graph->Nv - 1) */for (V=0; V<Graph->n; V++)for (W=0; W<Graph->n; W++)Graph->edges[V][W] = INF; /* 或INFINITY */return Graph;
}MGraph BuildGraph()
{ MGraph Graph;Edge E = (Edge)malloc(MAX_VERTEX_NUM * sizeof(struct ENode));int  V;int Nv, i;cout<<"请输入定点数"<<endl;scanf("%d", &Nv);Graph = CreateGraph(Nv);cout<<"请输入总边数"<<endl;scanf("%d", &(Graph->e));if ( Graph->e != 0 ) {for (i=0; i<Graph->e; i++) {cout<<"请输入边的信息,from,to,和权重"<<endl;scanf("%d %d %lf",&E->V1, &E->V2, &E->Weight);cout<<"请输入速度:"<<endl;scanf("%d",&speed[E->V1][E->V2]);/* 插入边 <V1, V2> */Graph->edges[E->V1][E->V2] = E->Weight;}}
/* 如果顶点有数据的话,读入数据 *//*   for (V=0; V<Graph->n; V++){scanf(" %c", &(Graph->vex[V]));}*/return Graph;
}
void Dijkstra(Mgraph g,int v,double dist[],int path[]){int i,j,u;double min;bool collected[MAX_VERTEX_NUM];/*从这句开始对各数组进行初始化*/for (int i = 0; i < g.n; ++i) {dist[i] = g.edges[v][i];collected[i] = false;if(g.edges[v][i]<INF)path[i] = v;elsepath[i] = -1;}collected[v] = true; path[v] = -1;for (int k = 0; k < g.n-1; ++k) {min = INF;//v = 未收录顶点中dist的最小者for (int i = 0; i < g.n; ++i) {//如果该点没有被收录,且路径小于当前的最小值if(collected[i]==false && dist[i]<min){u=i;min = dist[i];}}collected[u] = true; //将选出的点并入最短路径中//如果不存在,则breakfor (int i = 0; i < g.n; ++i) {/*这个if语句判断顶点u的加入是否会出现通往顶点j的更短的路径,如果出现,则改变原来路径及其长度,否则什么都不做*/if(collected[i]==false && dist[u]+g.edges[u][i] < dist[i]){dist[i] = dist[u]+g.edges[u][i];path[i] = u; //更新前面的节点}}}
}主程序main函数
int main(){MGraph graph = (MGraph )malloc(sizeof(MGraph)); graph= BuildGraph(); //建图Dijkstra(*graph,0,dist,path); //求最短路径... addSpeed(graph,speed);//增加速度Dijkstra(*graph,0,dist,path);//求最短时间...
}

三、测试

1、方案
方案:根据指导书上的图结点创建图。


成功创建图结点
2、结果(第一个是最短路径的dist和path数组,第二个是最短时间的dist和path数组)

最后将这些数据传输到前端,方便展示到达目的地的最短路径和最短时间,手动选择目的地将会根据path数组把经过的结点标记为橙色

结果检验:
手动笔算最短路径和最短时间看是否与之输出结果对应。
V1->v9:最短路径27,最短时间约等于8/10。
结果与之对应,正确。

四、总结与讨论

本次实验主要我主要运用了迪杰特斯拉算法来求带权图的最短路径和最短时间,此算法理解时容易,但通过代码实现的时候会遇到很多不理想的情况,比如需要通过bool类型数组确定节点是否被收录过,通过dist和path数组来交替赋值,细节上慢慢改动才成功实现了该算法,然后求最短时间加入了一个二维数组来代替每条边的速度。
遇到的问题:①数据类型的定义,在求最短时间时,使用int型的路程、速度、领接矩阵然后通过公式T=S/V算出来的值不精确,导致结果错误,后来改动为double类型才正确②单独开一个二维数组存放时间增加了空间复杂度,再进行第二次迪杰特斯拉算法也增加时间复杂度,应该在设计边节点时加入速度,然后使用领接表比较好弄,不过因为设计的时候选了领接矩阵所以不好改动③在进行数据输出为图像的时候使用了前端的知识,起初选中的顶点不会变色,后来自己查询了相关的css知识使之成功变橙色。

程序的源代码
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <fstream>
using namespace std;#define MAX_VERTEX_NUM 9  //顶点最大个数
#define INF 999
typedef struct {int no; //定点编号char info; //定点信息
}VertexType; //定点类型
typedef struct GNode *PtrToGNode;typedef struct GNode{double edges[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//领接矩阵的定义int n,e;//顶点数和边数VertexType vex[MAX_VERTEX_NUM];//存放定点的信息
}Mgraph;
typedef PtrToGNode MGraph;typedef struct ENode *PtrToENode;
struct ENode {int V1, V2; /* 有向边<V1, V2> */double Weight; /* 权重km */int speed;/* 速度km/h */
};
typedef PtrToENode Edge;
/*** 迪杰特斯拉最短路径算法* @param g 领接矩阵的图* @param v 起始顶点* @param dist 存放V到每个节点的最短路径的数组* @param path 存放每个节点的前驱节点*/
void Dijkstra(Mgraph g,int v,double dist[],int path[]);
/*** 目的是通过键盘输入创建图* @return*/
MGraph BuildGraph();
/*** 通过输入的顶点数初始化图,方便BuildGraph函数调用* @param VertexNum 顶点数* @return 返回初始化成功的图*/
MGraph CreateGraph( int VertexNum );
/*** 打印dist和path两个数组*/
void printMap();
/*** 目的是在边图中增加速度的数据* @param g 原来没有速度的图* @param speed 跟图一样的数组,但是对应的坐标存放的是速度*/
void addSpeed(Mgraph *g,int speed[][MAX_VERTEX_NUM]);
/*** 把最后关键的数据,返回到文件中,然后通过数据展示构建图在前端页面上* @param path 存放的路径* @param data 存放的数据*/
void writeFile(string path,string data);static double dist[MAX_VERTEX_NUM];
static int path[MAX_VERTEX_NUM];
static int speed[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
void test(int dist[]);
int main(){MGraph graph = (MGraph )malloc(sizeof(MGraph));graph= BuildGraph();Dijkstra(*graph,0,dist,path);writeFile("D:\\map.txt",dist);addSpeed(graph,speed);Dijkstra(*graph,0,dist,path);writeFile("D:\\map.txt",dist);
}
// 写文件
void writeFile(string path,double data)
{//1、创建输出流对象,并打开ofstream ofs(path,ios::out);//2、写文件for (int i = 0; i < MAX_VERTEX_NUM; ++i) {ofs<<data<<endl;}//3、关闭文件ofs.close();
}
void addSpeed(Mgraph *g,int speed[][MAX_VERTEX_NUM]){for (int i = 0; i < g->n; ++i)for (int j = 0; j < g->n; ++j) {if(g->edges[i][j]!=INF && speed[i][j]!=0){double t =(g->edges[i][j]/(speed[i][j]*1.0));g->edges[i][j] = t;}}
}typedef int Vertex; /* 用顶点下标表示顶点,为整型 */
MGraph CreateGraph( int VertexNum )
{ Vertex V, W;MGraph Graph;Graph = (MGraph )malloc(sizeof(MGraph));Graph->n = VertexNum;Graph->e = 0;
/* 注意:这里默认顶点编号从0开始,到(Graph->Nv - 1) */for (V=0; V<Graph->n; V++)for (W=0; W<Graph->n; W++)Graph->edges[V][W] = INF; /* 或INFINITY */return Graph;
}MGraph BuildGraph()
{ MGraph Graph;Edge E = (Edge)malloc(MAX_VERTEX_NUM * sizeof(struct ENode));int  V;int Nv, i;cout<<"请输入定点数"<<endl;scanf("%d", &Nv);Graph = CreateGraph(Nv);cout<<"请输入总边数"<<endl;scanf("%d", &(Graph->e));if ( Graph->e != 0 ) {for (i=0; i<Graph->e; i++) {cout<<"请输入边的信息,from,to,和权重"<<endl;scanf("%d %d %lf",&E->V1, &E->V2, &E->Weight);cout<<"请输入速度:"<<endl;scanf("%d",&speed[E->V1][E->V2]);/* 插入边 <V1, V2> */Graph->edges[E->V1][E->V2] = E->Weight;}}
/* 如果顶点有数据的话,读入数据 *//*   for (V=0; V<Graph->n; V++){scanf(" %c", &(Graph->vex[V]));}*/return Graph;
}void Dijkstra(Mgraph g,int v,double dist[],int path[]){int i,j,u;double min;bool collected[MAX_VERTEX_NUM];/*从这句开始对各数组进行初始化*/for (int i = 0; i < g.n; ++i) {dist[i] = g.edges[v][i];collected[i] = false;if(g.edges[v][i]<INF)path[i] = v;elsepath[i] = -1;}collected[v] = true; path[v] = -1;for (int k = 0; k < g.n-1; ++k) {min = INF;//v = 未收录顶点中dist的最小者for (int i = 0; i < g.n; ++i) {//如果该点没有被收录,且路径小于当前的最小值if(collected[i]==false && dist[i]<min){u=i;min = dist[i];}}collected[u] = true; //将选出的点并入最短路径中//如果不存在,则breakfor (int i = 0; i < g.n; ++i) {/*这个if语句判断顶点u的加入是否会出现通往顶点j的更短的路径,如果出现,则改变原来路径及其长度,否则什么都不做*/if(collected[i]==false && dist[u]+g.edges[u][i] < dist[i]){dist[i] = dist[u]+g.edges[u][i];path[i] = u; //更新前面的节点}}}
}

城市交通咨询模拟系统,利用该系统实现至少两种最优决策:最短路程到达、最省时到达等线路规划。相关推荐

  1. 数据结构实验:城市交通咨询模拟系统

    一. 实验目的 1.目的:掌握图的存储.构建.搜索等操作和应用,能用最短路径及其搜索等算法编制较综合性的程序,求解最优路线问题,进行程序设计.数据结构和算法设计等方面的综合训练. 2.任务:设计一个城 ...

  2. 给图像增加一种噪声,构造并利用至少两种高通滤波器实现频率域的滤波

    给图像增加一种噪声,构造并利用至少两种高通滤波器实现频率域的滤波 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页.如果你想学习如何使用Markdown ...

  3. 用ChatGPT处理word表格数据:直接采用ChatGPt和利用ChatGPT编写python脚本两种方法

    目录 摘要 0. 测试数据生成 1. 直接使用ChatGPT进行处理. 2 使用ChatGPT生成python脚本进行处理 3对比分析 4 结束语 摘要 为测试ChatGP在word文档表格的处理能力 ...

  4. 用matlab计算稳态误差,利用Matlab求稳态误差的两种方法.

    利用Matlab求稳态误差的两种方法 摘要:稳态误差是系统控制精度或抗扰动能力的一种度量,它是稳态性能的一个重要指标.本文介绍利用Matlab的控制系统工具箱和Simulink工具箱求取系统误差稳态的 ...

  5. (Dijkstra算法)设计实现一个全国大城市间的交通咨询程序,为旅客提供三种最优决策方案:(1)飞行时间最短(2)费用最小(3)中转次数最少。

    设计实现一个全国大城市间的交通咨询程序,为旅客提供三种最优决策方案: (1)飞行时间最短 (2)费用最小 (3)中转次数最少 数据如下: 机  号 出 发 地 到 达 地 出发时间 到达时间 费  用 ...

  6. [css] 如何重写行内样式?方法有哪些(至少两种)?

    [css] 如何重写行内样式?方法有哪些(至少两种)? 1, !important 最高级 2, var divStyle = document.querySelector('#div').style ...

  7. 正则数字字母下划线至少两种_8085微处理器中至少两个8位数字

    正则数字字母下划线至少两种 Problem statement: 问题陈述: To find minimum of two 8bit numberusing 8085 microprocessor. ...

  8. 正则表达式强密码验证: 8-16个字符,不包含空格,必须包含数字,字母或字符至少两种

    验证需求: 8-16个字符,不包含空格,必须包含数字,字母或字符至少两种 正则表达式: /(?!.*\s)(?!^[\u4e00-\u9fa5]+$)(?!^[0-9]+$)(?!^[A-z]+$)( ...

  9. Macbook系统清理的两种方式

    你在使用mac系统吗?很多的用户朋友都以为mac系统是不需要清理的,其实不是这样的.虽然其有自动清理功能,还是会有一些垃圾残留的.Macbook系统清理有两种常见的方式:手动清理和使用第三方软件. 手 ...

最新文章

  1. 【.Net MF网络开发板研究-04】Socket编程之服务端
  2. 【进展】温度监测报警器(系统)作品项目快发布了!
  3. ASP.NET2.0中themes、Skins轻松实现网站换肤!
  4. 原生JS大揭秘—数据类型
  5. 温州动车事故中受伤的“我”,还好吗?
  6. Swift2.0新特性
  7. android 生成车牌号,android 车牌号识别系统app源码
  8. Python:Excel转TXT的简单办法
  9. 21世纪什么最值钱?“人脸”
  10. 专业家庭影院功放推荐-数字功放芯片
  11. 精彩博文收集目录索引
  12. 你的Web系统真的安全吗?
  13. 同步通信和异步通信的爱恨情仇
  14. 布尔定律---布尔代数的基本定律
  15. matlab中sym看不到值和属性,matlab 用sym定义了x,但是输入函数却显示“未定义函数或变量 'x'”?...
  16. Primo Ramdisk内存盘工具软件
  17. 实时自动驾驶车辆定位技术都有哪些?(视觉/Lidar/多传感器数据融合)
  18. 计算机辅助工业设计应用软件,计算机辅助工业设计(CAID)
  19. 我最喜欢的计算机专业课作文,我喜欢电脑课作文
  20. linux代码段 java_java代码可以导致linux中的分段错误吗?

热门文章

  1. 为什么Django还是比Flask好一点点?
  2. 应用ArcGIS Pro深度学习(Deep Learning)模块识别棕榈树案例
  3. NEU 1212 VIJOS-P1037
  4. ECS阿里云服务器默认禁了smtp 端口25 无法发送邮件
  5. 对外SMTP(TCP25端口)发送邮件的情况处理
  6. flask+Vue基于web的旅游信息管理系统python django
  7. 数据结构与算法:求员工工资问题
  8. 媒体查询(@media语法、案例)详解
  9. Hyperf 接入阿里云ACM应用配置管理中心
  10. JPEG图像压缩算法的python实现