目录
问题:
背景知识:图的存储、遍历及其应用,图的最短路径等。
目的要求:
掌握图的存储、构建、搜索等操作和应用,能用最短路径及其搜索等算法编制较综合性的程序,求解最优路线问题,进行程序设计、数据结构和算法设计等方面的综合训练。
实验内容:
1.任务:设计一个城市交通咨询模拟系统,利用该系统实现至少两种最优决策:最短路程到达、最省时到达等线路规划。
2.内容:
用户驾车出行由于出行目的的不同对道路路线选择的要求也有不同。例如,有的希望在途中的路程尽可能短,有的则可能希望路程中时间最短。为了能满足广大旅客的需求,编制一个城市交通咨询模拟系统,选取城市部分位置、道路抽象为程序所需要图的顶点和边,并以城市道路长度(路程),道路的某时段的速度等信息作为图结点中的弧信息,为旅客提供这两种最优决策的交通咨询。
实验说明:
1.输入和输出:
(1)输入形式:
- 构建图时,输入顶点、弧涉及的信息,包括:起始地、目的地、长度、该弧此时间段的平均速度等信息;
- 用户或者客户要输入出发地和目的地,并选择何种最优决策的路线规划。
(2)输出形式:根据用户需求输出对应信息
- 输出最短路程所需要的路线信息和最短路程;
- 输出最短时间所需要的路线信息和最短时间。
2.实验要求:
-
- 实现一个简单的交互式界面,包括系统菜单、清晰的输入提示等。
- 根据输入的交通图数据,以图形化形式把交通图显示在屏幕上。
- 以图形化形式把最优路线显示在屏幕上。
代码1(这是题目给的代码)
解析:
这个是实验指导书上的源码,挺好用
功能1:
首先建立三个文本文件
count文件里面存的地方的个数,map文件里面存的是一个点到另一个点的距离,map_speed文件里面存的是 一个点到另一个点的时间
看map里面的1,处于第1行第2列,就是第一个点到第二个点的距离是1,
map_speed的1.1就是第1个点到第2个点的花费的时间是1.1
这是我用的测试点
下面正式开始测试,首先你要改一下代码中的文件的路径,
运行结果图
我们可以根据之前的测试图,可以看到它的路线
功能2:
录入路线
把代码中的写入的路径更改一下
这个输入的是两个点是双向都可以通的,点1到点2 的距离是1速度是1,
思路:很简单,就是用弗罗伊德算法,计算出权值最小的路径,顺便用记录中间的一些中转点,在最后的输出路径中输出出来。
弗罗里达算法思想,想具体知道弗罗里达算法算法自己在网上搜一下吧看吧。
代码
稍微加了一些注释,这个给的代码很简单,应该不用多说吧,不会真的有人看不懂吧
#include <stdio.h>
#include <stdlib.h>
#define inf 99999999
#define max_element 50
int e[max_element][max_element]; //保存地图的数组
int path_e[max_element][max_element], path_t[max_element][max_element];//转折点的路径
double t[max_element][max_element]; //保存地图的速度
void Menu();
void Old_Map();
void New_Map();
void Floyd(int (*e)[max_element],double (*t)[max_element], int n); //计算最短路径
void Floyd_dist(int (*e)[max_element], int n, int start, int end);
void Floyd_time(double (*e)[max_element], int n, int start, int end);
int main()
{
int Mu=5;
Menu();
while(scanf("%d", &Mu), Mu!=0)
{
switch(Mu)//菜单选项
{
case 1: Old_Map();break;
case 2: New_Map();break;
case 3: system("cls");break;
default:printf("\n请输入正确指令!!!");break;
}
Menu();
}
printf("\n成功退出!");
return 0;
}
void Menu()
{
printf("\n ---选择使用已保存的地图:1---");
printf("\n\n ---选择重新录入地图信息:2---\n");
printf("\n -----------清屏:3-----------\n");
printf("\n -------------退出:0-------------\n");
}
//使用原有地图
void Old_Map()
{
int i, j;
FILE *fp;
int count = 0;
//读入文档count.txt
if((fp=fopen("C:\\Users\\jin\\Desktop\\count.txt","r")) == NULL)
{
printf("File open failed!\n");
exit(0);
}
fscanf(fp,"%d", &count);//读入点数
fclose(fp);
printf("顶点个数 == %d\n", count);
if(count == 0 )
{
printf("\n信息读入错误!!\n错误原因:没有已保存的地图,请选择重新输入地图信息!!\n");
return ;
}
///读入文档map.txt
if((fp=fopen("C:\\Users\\jin\\Desktop\\map.txt","r")) == NULL)
{
printf("File open failed!\n");
exit(0);
}
for(i = 1; i <= count; i++)
for(j = 1; j <= count; j++)
{
fscanf(fp,"%d", &e[i][j]);
}//读入距离地图,是一个矩阵
fclose(fp);
///读入文档map_speed.txt
if((fp=fopen("C:\\Users\\jin\\Desktop\\map_speed.txt","r")) == NULL)
{
printf("File open failed!\n");
exit(0);
}
for(i = 1; i <= count; i++)
for(j = 1; j <= count; j++)
{
fscanf(fp,"%lf", &t[i][j]);
}//读入时间地图,矩阵
fclose(fp);
///将地图信息打印*************能否采用图形界面将位置信息打印?
Floyd(e,t, count);
}
//新录入地图
void New_Map()
{
//map数组初始化
int i, j;
for(i = 0; i < max_element; i++ )
for(j = 0; j < max_element; j++)
if(i == j)
{
e[i][j] = 0;
t[i][j] = 0;
}
else {
e[i][j] = inf;
t[i][j] = inf;
}
printf("\n请输入每条路的起点、终点、路的长度、速度\n(中间以空格隔开,按下Ctrl+Z结束输入):\n");
int s, ee, l, speed;
int count = 0;
//地图写入
while(scanf("%d %d %d %d", &s, &ee, &l,&speed) != EOF)
{//开始地,目标地,距离,速度
e[s][ee] = l;
e[ee][s] = l;
t[s][ee] = (l*1.0)/speed;
t[ee][s] = (l*1.0)/speed;
printf("%.2f ", t[s][ee]);
count++;
}
///将地图存入文件map.txt
FILE *fp;
if((fp=fopen("C:\\Users\\jin\\Desktop\\map1.txt","w")) == NULL)
{
printf("the file can not open...");
exit(0);
}
for(i = 1; i <= count; i++)
for(j = 1; j <= count; j++)
{
fprintf(fp,"%d", e[i][j]);
fprintf(fp,"\n");
}
fclose(fp);
///将速度-时间存入文件中"map_speed.txt
if((fp=fopen("C:\\Users\\jin\\Desktop\\map_speed1.txt","w")) == NULL)
{
printf("the file can not open...");
exit(0);
}
for(i = 1; i <= count; i++)
for(j = 1; j <= count; j++)
{
fprintf(fp,"%lf", t[i][j]);
fprintf(fp,"\n");
}//像文件里面写入速度(浮点数)
fclose(fp);
///将顶点的个数存入文件
if((fp=fopen("C:\\Users\\jin\\Desktop\\count1.txt","w")) == NULL)
{
printf("the file can not open...");
exit(0);
}
fprintf(fp,"%d", count);
fclose(fp);
Floyd(e,t, count);
}
//佛洛依德算法
void Floyd(int (*e)[max_element],double (*t)[max_element],int n)
{
int start, end; //起始位置,终点
//初始化记录路径详细信息数组path
int i, j;
//初始化终点***
for( i = 0; i <= n; i++)
for(j = 0; j <= n; j++)
{
path_e[i][j] = j;
path_t[i][j] = j;
}
while(1)
{
printf("\n请输入要查询路径起点、终点位置:");
scanf("%d %d", &start, &end);
if(start > n || end > n)
{
printf("\n出现错误!!!\n错误原因:输入了不存在的顶点!!\n请重新输入!!\n");
printf("\n顶点个数为:%d", n);
continue;
}
int Floyd_xuanze = 0;
printf("\n请输入查询方式:\n");
printf("1---最短路径\n");
printf("2---最短时间\n");
scanf("%d", &Floyd_xuanze);
/**
*异常处理
*/
switch(Floyd_xuanze)
{
case 1: Floyd_dist(e, n, start, end);break;
case 2: Floyd_time(t,n, start, end);break;
default : printf("请输入正确指令!!!\n");break;
}
int temp = 0;
printf("是否继续查询:yes:1 / no:0\n");
scanf("%d", &temp);
if(!temp)
break;
}
}
void Floyd_dist(int (*e)[max_element], int n, int start, int end)
{
int k, i, j;
///佛洛依德算法---距离
for(k = 1; k<=n; k++)//中转点
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
if(e[i][j]>e[i][k]+e[k][j])
{
e[i][j]=e[i][k]+e[k][j];
path_e[i][j] = path_e[i][k];//记录中转点
}
///打印出最短路径及相应路径信息--距离
printf("\n查询成功!!信息如下:\n\n");
printf("%d=>%d, length:%d, ",start, end, e[start][end]);
int v = path_e[start][end];//最开始的中转点
printf("path:%d", start);
while(v!=end)
{
printf("->%d",v);
v = path_e[v][end];
}
printf("->%d", end);
printf("\n___________________________________________\n");
}
void Floyd_time(double (*t)[max_element], int n, int start, int end)
{
int k, i, j;
///佛洛依德算法---时间
for(k = 1; k<=n; k++)
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
if(t[i][j]>t[i][k]+t[k][j])
{
t[i][j]=t[i][k]+t[k][j];
path_t[i][j] = path_t[i][k];
}
///打印出最短路径及相应路径信息--距离
printf("\n查询成功!!信息如下:\n\n");
printf("%d=>%d, time:%.2fh, ",start, end, t[start][end]);
int v = path_t[start][end];
printf("path:%d", start);
while(v!=end)
{
printf("->%d",v);
v = path_t[v][end];
}
printf("->%d", end);
printf("\n___________________________________________\n");
}
代码2(自己写的)
前言
如果你这个看的不是很懂,建议看第一个,
其实也没啥,就是实现一个中文的地点,用map容器进行映射。
其中的难点就是搞了我好久的一个小东西,读取文件,一个词,一个词的读取,搞得我很头疼,不过最后巧妙的解决啦
这个东西如果只用getline(ifs, read, ' '),读取文件的时候,当读取到第一行最后一个词的时候,会和第二行第一个词一起读,于是乎,可能应该搞了有点长时间把,想了一个巧妙的办法给解决啦,唉这就是生活啊,兵来将挡,水来土掩。
整体思路及运行情况
思路:读取文件里面给的路线图,把这些点用弗罗伊德算法,算出最优解,根据所求,输出所要。
主要的亮点就是中文的地点,用了map容器进行一些替换
运行情况:
首先把你的文件调整成ANSI编码,
在文件的输入格式是,开始地名,目的地名,距离(浮点型),速度(浮点型)
这是我的地图,画了一下
开始运行,首先你要知道你的文件的路径
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
map<string,int> pp;
map<int,string> qq;
#define inf 99999999
double dist[50][50],timee[50][50];
int locations = 0;
void Floyd(double mn[50][50],int choose);
void Choose();
void Floyd(double mn[50][50],int choose)
{
int path_min[50][50];//记录中间转折点
for(int i=1; i<=locations; i++)
for(int j=1; j<=locations; j++)
if(i!=j&&mn[i][j]==0)
{
mn[i][j] = inf;//初始化地图
//cout<<dist[i][j]<<endl;
}
for(int i=1; i<=locations; i++)
for(int j=1; j<=locations; j++)
{
path_min[i][j] = j;//初始化转折点
}
//弗罗里达算法
for(int k = 1; k<=locations; k++)
for(int i=1; i<=locations; i++)
for(int j=1; j<=locations; j++)
{
if(mn[i][j]>mn[i][k]+mn[k][j])
{
mn[i][j] = mn[i][k]+mn[k][j];
path_min[i][j] = path_min[i][k];
}
}
while(1)
{
printf("请输入出发地名和目的地名\n");
printf("出发地名:");
string ss;
cin>>ss;
int st = pp[ss];
printf("目的地名:");
string sss;
cin>>sss;
int ed = pp[sss];
cout<<"++++++++++++++++++++++++"<<endl;
cout<<(choose == 1 ? "您所需的最短路程为:":"最短时间为:");
cout<<mn[st][ed];
cout<<(choose == 1 ? "公里" : "小时")<<endl;
cout<<"++++++++++++++++++++++++"<<endl;
cout<<"您的路线为:"<<endl;
cout<<"------------------------"<<endl;
cout<<ss<<"->";
int v = path_min[st][ed];
while(v!=ed)
{
cout<<qq[v]<<"->";
v = path_min[v][ed];
}
cout<<sss<<endl;
cout<<"------------------------"<<endl;
cout<<"请问是选择再次询问,还是退出,还是返回上一级"<<endl;
cout<<"\t1再次询问\n"<<"\t2.返回上一级\n"<<"\t3.退出\n"<<endl;
int c;
cin>>c;
if(c==1) {}
else if(c==2)
Choose();
else if(c==3)
return;
}
}
void Choose()
{
printf("请选择查询方式\n");
printf("1.最短路径\t");
printf("2.最短时间\t\n");
int choose;
cin>>choose;
if(choose==1)
{
Floyd(dist,choose);//最短路程
}
else if(choose==2)
{
Floyd(timee,choose);//最少时间
}
else
{
cout<<"您输入的指令有误,请重新输入"<<endl;
Choose();
}
}
int main()
{
int id=1;
cout<<"请输入您地图的位置"<<endl;
string Path;
cin>>Path;//输入位置
char path[100];
for(int i=0; i<Path.length(); i++)
path[i] = Path[i];
ifstream ifs(path);
if(ifs!=NULL) cout<<"您的地图已被打开已经被打开"<<endl;
string read;
int ans = 0;
string start,end;//出发地,目标地
double dis,sp;//距离,速度
while(getline(ifs, read, ' '))
{
if(ans%4==0)//读取的第一个词
{
start = read;
//cout<<"开始地"<<read<<endl;
}
if(ans%4==1)//读取的第二个词
{
end = read;
//cout<<"目标地"<<read<<endl;
}
if(ans%4==2)//读取的第三个词和第四个词
{
char s1[10];
memset(s1,0,sizeof(s1));
for(int i=0; i<read.length(); i++)
s1[i] = read[i];
dis = atof(s1);
//cout<<dis<<"距离"<<read<<endl;
getline(ifs, read, '\n');
char s2[10];
for(int i=0; i<read.length(); i++)
s2[i] = read[i];
sp = atof(s2);
// cout<<"速度"<<read<<endl;
ans++;
}
//cin>>start>>end>>dis>>sp;
if(ans%4==3)//四个读取完开始储存
{
if(pp[start]==0)//如果这个地点没有被储存,便开始储存
{
pp[start] = id;//地点对应的序号
qq[id] = start;
id++;
}
if(pp[end]==0)
{
pp[end] = id;
qq[id] = end;
id++;
}
dist[pp[start]][pp[end]] = dis;//这段路的而距离
timee[pp[start]][pp[end]] =dis/sp;//这段路的时间
//cout<<dist[pp[start]][pp[end]]<<"--"<<timee[pp[start]][pp[end]]<<endl;
}
ans++;
}
map<string,int>::iterator it;
for(it = pp.begin(); it!=pp.end(); it++)
{
locations++;//统计共有几个地点
//cout<<it->first<<"--"<<it->second<<endl;
}
/*for(int i=1; i<=5; i++)
{
cout<<qq[i]<<endl;
}*/
//cout<<locations<<endl;
Choose();
return 0;
}