最便宜航空路线求解.docx
《最便宜航空路线求解.docx》由会员分享,可在线阅读,更多相关《最便宜航空路线求解.docx(39页珍藏版)》请在冰豆网上搜索。
最便宜航空路线求解
学号:
课程设计
题目
最便宜航空线路求解
学院
管理学院
专业
信息管理与信息系统
班级
姓名
指导教师
2014
年
07
月
03
日
课程设计任务书
学生姓名:
专业班级:
信管
指导教师:
工作单位:
管理学院
题目:
最便宜航空线路求解
初始条件:
【问题描述】
飞机是远途旅行必不可少的工具,但是高昂的价格也令人颇费思量,因此人们往往宁愿用时间来换金钱而选择较慢的交通工具。
不过,当航班线路变得丰富之后,人们也发现很多时候选择直达航班往往并非最省钱的路径,比如飞往美国选择从韩国转机就比直飞要便宜多了(虽然这样有坠机的危险)。
这样一来,当采用曲线行进能达到省钱也省时间的目的时,坐飞机还是可以接受的。
为了能够更好地解决路径的选择问题,我们模拟一下通过合适的算法来选出最优航空线路。
参考
要求完成的主要任务:
(包括课程设计工作量及其技术要求、说明书撰写等具体要求)
本程序不考虑机场建设费和燃油附加费,只计算机票价格,将其作为路径上的权值处理,耗费矩阵存储结构自行选择。
在真实的情形中,同一线路每天可能有许多航班,也可能每周只有一两趟航班,即便同一天的航班早晚价格也可能有所不同。
为简便计,假定每条线路每天只有一趟航班,不考虑航空公司的差别。
时间安排:
序号
设计内容
所用时间
1
问题分析和任务定义
0.5天
2
数据类型和系统设计
0.5天
3
编码实现和静态检查
3天
4
上机准备和上机调试
2天
5
总结和整理设计报告
1天
合计
7天
指导教师签名:
2014年06月25日
系主任(或责任教师)签名:
2014年06月25日
最便宜航空线路求解
1.需求分析
1.1基本要求
(1)所有原始数据一律事先用文本文件保存,读入数据时从文件获取。
(2)航班价格可以用随机函数生成,但建议从网上直接复制真实数据。
(3)可输出所有城市名称以及每一城市所有可直飞到达的城市列表。
(4)可输出任一指定直飞线路(若没有则显示无直飞航班)四个季度的全票和折扣价格。
(5)输入月份、起始城市和目的城市名称,程序能显示出最经济的中转路线选择方案。
1.2输入
(1)从文件read.txt中读取不同城市之间(共10个城市)不同航线(共24条航线)的最高价格输入,四个季度有相同的最高价格。
(2)每条线路每季度的折扣率由随机函数产生,范围是0.20~1.00(小数点后取两位),四个季度有不同的折扣。
(3)运行程序时需根据要求从键盘输入相应指令,保证程序的正确运行。
1.3输出
(1)输出所有城市名以及每一城市所有可直飞到达的城市列表(按城市名拼音升序排列):
始发地可直飞目的地
北京长春广州杭州昆明上海首尔武汉香港
……
首尔北京上海台北香港
……
(2)输出指定线路四个季度的折扣和全价:
输入:
北京-台北
输出:
无直飞航班
输入:
北京-广州
输出:
季度全票价格折扣折后价格(不计小数,四舍五入)
112406.5806
211927.0834
314754.6679
412308.71070
(3)输入月份、起始城市和目的城市名称,输出最佳方案:
输入:
5北京-台北
输出:
最佳线路:
北京-香港,1503,香港-台北,791,合计2294
输入:
7广州-首尔
输出:
最佳线路:
广州-上海,880,上海-首尔,773,合计1653
输入:
10武汉-上海
输出:
最佳线路:
武汉-上海,278,合计278
……
1.4测试数据
文本文件read.txt内容:
(1)读文本文件read.txt。
若文件名输入正确且文件无错误,则显示主菜单。
若文件名输入错误或文件有错误,则显示“打开输入文件出错”。
(2)根据主菜单提示选择需要执行的功能。
若输入功能序号在0—4之间,则执行相应的功能。
若输入功能序号不在0—4之间,则显示“出错啦请在0-4之间选择!
!
”和主菜单,需重新选择。
(3)选择1,输出城市列表及相应代码。
(4)选择2,输出所有城市名以及每一城市所有可直飞到达的城市列表(按城市名拼音升序排列)。
(5)选择3,先显示城市列表及相应代码,方便后面的输入操作,根据提示“请输入起始城市和目的城市的代码,中间以空格隔开,范围(1--10)”输入两个城市代码,若两城市间有直飞航班则显示指定线路四个季度的折扣和全价。
若两城市间无直飞航班则显示“无直飞航班”。
(6)选择4,显示“请输入月份(请在1-12之间选择):
”若月份输入正确,则先显示城市列表及相应代码,方便后面的输入操作,根据提示“请输入起始城市和目的城市的代码,中间以空格隔开,范围(1--10)”输入两个城市代码,若代码输入正确,则显示最佳方案。
若月份输入错误,则显示“输入出错”。
若城市代码输入错误,则显示“出错啦”。
(7)选择0,则直接退出程序。
(8)在每一个功能执行完后,都会提示继续执行还是返回主菜单。
1.5无向带权费用图
2.概要设计
2.1抽象数据类型定义
本程序运用了关于图这种数据结构,它的抽象数据类型定义如下:
typedefstructunDiGraph
{
intnumVerts;//结点
costAdjcost;//邻接矩阵
}unDiGraph,*UNG;
基本操作:
unDiGraph*CreateCostG()
操作结果:
构造带权(费用)图。
PathMat*Floyed(unDiGraph*D)
操作结果:
Floyed函数
求任意两点的最短路径。
2.2主程序流程及各程序模块之间的层次(调用)关系
pr(i,0)Floyed()Floyed()
pr(Bcity,0)pr(Bcity,0)
prn_pass(Bcity,Ecity)prn_pass(Bcity,Ecity)
pr(Ecity,0)pr(Ecity,0)
3.详细设计
3.1数据类型
(1)主界面包括
1.查看城市
2.输出所有城市名及所有可直飞到达的城市列表(按城市名拼音升序排列)
3.输入起始城市和目的城市名称,输出指定线路四个季度的折扣和全价
4.输入月份、起始城市和目的城市名称,输出最佳方案
0.退出程序
(2)程序的模块为
#include
#include
#include//需引用的头文件
#defineINF65535//定义一个最大数为无穷值,表示两城市之间无直飞航班
#defineMAX23
typedefintcostAdj[MAX+1][MAX+1];//图邻接矩阵从1开始记数
intPath[MAX+1][MAX+1];//图邻接矩阵从1开始记数
typedefstructunDiGraph
{
intnumVerts;//结点
costAdjcost;//邻接矩阵
}unDiGraph,*UNG;//图的定义
costAdjB,L;
voidpr(inti)//选择城市
voidpri()//输出城市
unDiGraph*CreateCostG()//构造带权(费用)图返回首地址G:
voidFloyed(unDiGraph*D,unDiGraph*M)//Floyed函数求任意两点的最短路径:
voidprn_pass(inti,intj)//为了求从i到j的最短路径,只需要调用如下的过程
voidf_money1()//输出所有城市名及所有可直飞到达的城市列表(按城市名拼音升序排列)
voidf_money2()//输入起始城市和目的城市名称,输出指定线路四个季度的折扣和全价
voidf_money4()//输入月份、起始城市和目的城市名称,输出最佳方案
intLineNumStat(FILE*fp)//统计文本文件的行数
voidmain()//main函数
3.2伪码算法
(1)pr()选择城市
begin
0=>h
Ifj=0thenh=i
Elseifj=1inputadd[i].a
Switch条件选择print城市名
End
(2)pri()输出城市
begin
Print城市代码
1=>i
Whilei<=c_number
{
Printi
调用pr()函数
}
End
(3)unDiGraph*CreateCostF(into)飞机花费的存贮功能
Begin
0=>a,0=>b,1=>h
Wuhan[10],Beijing[10],Xiamen[10],Guangzhou[10],Dalian[10],
Shanghai[10],Changsha[10],Shenzhen[10],Zhengzhou[10],Tianjin[10]
G=(unDiGraph*)malloc(sizeof(unDiGraph)
If!
GthenNULL
1=>i
Whilei{
WhilejINF=>G->cost[i][j]初始化使G->cost[i][j]为无穷。
}
c_number=>G->numVerts
while(!
feof(fp))
fscanffp,"%f%f%f%f%f%f%f%f%f%f",&Wuhan[i],&Beijing[i],&Xiamen[i],&Guangzhou[i],&Dalian[i],&Shanghai[i],&Changsha[i],&Shenzhen[i],&Zhengzhou[i],&Tianjin[i]
for(0=>j;j{
Wuhan[j-1]=>G->cost[j][1]
Beijing[j-1]=>G->cost[j][2]
Xiamen[j-1]=>G->cost[j][3]
Guangzhou[j-1]=>G->cost[j][4]
Dalian[j-1]=>G->cost[j][5]
Shanghai[j-1]=>G->cost[j][6]
Changsha[j-1]=>G->cost[j][7]
Shenzhen[j-1]=>G->cost[j][8]
Zhengzhou[j-1]=>G->cost[j][9]
Tianjin[j-1]=>G->cost[j][10]
}
return(G);
}
End
(4)Floyed(unDiGraph*D,unDiGraph*M)函数Floyed函数求任意两点的最短路径
Begin
c_number=>n
1=>i
while(i<=n)
{
1=>j
while(j<=n)
{
D->cost[i][j]=>A[i][j]初始化矩阵A。
M->cost[i][j]=>C[i][j]
-1=>Path[i][j]初始化矩阵p,置-1.
}
}
for(0=>k;k<=n;k++)为逐步加入的中间结点
{
for(0=>i;i<=n;i++)i为A中行号
{
for(0=>j;j<=n;j++)
if(A[i][k]+A[k][j]then{A[i][k]+A[k][j]=>A[i][j]
K=>Path[i][j]若i经过k到j比i到j小,则令A[i][j]=A[i][k]+A[k][j]
A[i][j]=>B[i][j]
}
else{
A[i][j]=>B[i][j]
}
}
}
print最短路径为:
End
(5)prn_pass(inti,intj)输出最短路径所经过的点
Begin
If(Path[i][j]!
=-1)
{
递归调用prn_pass(i,Path[i][j])
调用pr(Path[i][j],0)
}
End
(6)f_money1()输出方式1函数
Begin
l
1=>h
do{
Print始发地可直飞目的地
Print北京广州武汉
Print长沙大连天津
Print大连长沙厦门郑州
Print广州北京上海郑州
Print上海广州深圳天津
Print深圳上海天津
Print天津长沙上海深圳
Print武汉北京厦门
Print厦门大连武汉
Print郑州长沙广州
Print1.继续输出所有城市名以及每一城市所有可直飞到达的城市列表2.返回主菜单清选择...
inputl输入1或2选择是否继续。
1=>h
}
End
(7)f_money2()输出方式2函数
Begin
1=>h
Bcity,Ecity//起始成市号码和终点城市号码
l
money[4]
i,j
s,w
discount[4]
while(h==1)
{
print请输入起始城市和目的城市的代码,中间以空格隔开,范围(1--%d,c_number
inputBcity
inputEcity输入起始城市和终点城市的代码。
if(!
((0=Ecity))
thenprint出错啦
exit
(1)
Floyed(CreateTimeF(0),CreateCostF(0))调用Floyed函数。
pr(Bcity,0)显示起始城市。
prn_pass(Bcity,Ecity)调用prn_pass函数,显示最短路径经过的城市。
pr(Ecity,0)显示终点城市。
if(B[Bcity][Ecity]>5000||L[Bcity][Ecity]>10000)
thenprint无直飞航班
else
{Print"季度全票价格折扣折后价格(不计小数,四舍五入)\n"
srand((unsigned)time(NULL))随机种子
for(0=>j;j<4;j++)
{
for(0=>i;i<100;i++)
{
if(!
(i%10))
rand()%80+20=>w
w/100=>s
break;
}
s=>discount[j]
}
for(0=>i;i<4;i++)
{
(floatdiscount[i]*B[Bcity][Ecity]=>money[i]
Print"%d%d%.2lf%.lf\n",i+1,B[Bcity][Ecity],discount[i],money[i]);
Print“打折前的费用是%d元\n",L[Bcity][Ecity]
}
Print1.继续输入起始城市和目的城市名称,输出指定线路四个季度的折扣和全价\n2.返回主菜单\n清选择...
inputl输入1或2选择是否继续。
1=>h
}
End
(8)f_money3()输出方式3函数
Begin
1=>h
Bcity,Ecity起始成市号码和终点城市号码
L
money
i,j
s,w
discount[4]
M
month
quarter
do{
Print"请输入月份(请在1-12之间选择):
"
Inputmonth
if(month>=12||month<=1)
{
Print"输入出错!
\n"
exit
(1);
}
pri()输出城市列表及相应代码。
print请输入起始城市和目的城市的代码,中间以空格隔开,范围(1--%d,c_number
inputBcity
inputEcity输入起始城市和终点城市的代码。
if(!
((0=Ecity))
{
Print\n出错啦\n"输入出错
exit
(1)关闭所有文件,终止正在执行的程序
}
Floyed(CreateCostF(0))调用Floyed函数。
if(B[Bcity][Ecity]>5000)
{
print无航班\n"
}
else{
srand((unsigned)time(NULL随机种子
for(0=>j;j<4;j++)
{
for(0=>i;i<100;i++)
{
if(!
(i%10))
rand()%80+20=>w
w/100=>s
break;
}
s=>discount[j]
}
if(1<=month<=3)
{
discount[0]=>m
1=>quarter
Print"你选择的是%d月,位于第%d季度,折扣是%.2lf\n",month,quarter,m
}
elseif(4<=month<=6)
{
discount[1]=>m
2=>quarter
Print"你选择的是%d月,位于第%d季度,折扣是%.2lf\n",month,quarter,m
}
elseif(7<=month<=9)
{
discount[2]=>m
3=>quarter
Print"你选择的是%d月,位于第%d季度,折扣是%.2lf\n",month,quarter,m
}
elseif(10<=month<=12)
{
discount[3]=>m
4=>quarter
Print"你选择的是%d月,位于第%d季度,折扣是%.2lf\n",month,quarter,m
}
(float)m*B[Bcity][Ecity]=>money
Print"最佳线路:
"
pr(Bcity,0)显示起始城市。
prn_pass(Bcity,Ecity)调用prn_pass函数,显示最短路径经过的城市。
pr(Ecity,0)显示终点城市。
Print"合计:
"
Print"%.lf\n",money
}
Print1.继续输入月份、起始城市和目的城市名称,输出最佳方案\n2.返回主菜单\n清选择...
inputl输入1或2选择是否继续。
1=>h
}
End
4.调试分析
4.1问题与解决办法
(1)声明变量语句的位置
我在运行的过程中一直出现这个错误(见下图),系统报错说未定义变量,但我确实定义过了,后来通过在网上XX资料才知道要把声明变量的语句得放到函数的最前面,而printf要放在 所有变量声明语句后面。
修改程序之后,那些错误果然没有了。
(2)文本文件的读取
程序在读取文本文件时总说打开文件出错,原因是read.txt中含有非法字符,删去即可。
而且在程序末尾要记得调用函数fclose(),关闭文件。
(3)把从文本文件读取的数据保存到数组中
编写这一部分的时候总是出现错误,主要是对指向数组的指针认识不清,通过这次编程对它有了更深的了解。
(4)scanf("%s",&add[i].a)和printf("%s",add[i-10].a)
在编写程序阶段,我最开始编写这两个函数的时候是scanf("%c",&add[i].a)printf("%c",add[i-10].a),当时没有看清add[i].a最初的定义,它其实是一个字符数组,所以在运行的时候老出错,后面慢慢研究和调试才知道在输入和输出的格式占位符应该用%s.
(5)随机函数的编写
我以前几乎没接触过随机函数,所以对其不是很了解。
刚开始的时候都不会写,后来在网上找实例,才知道其用法。
而且根据题目的要求产生折扣的范围是0.20~1.0(小数点后取两位),所以要产生有小数范围的不同随机数,就要用时间作为产生随机数的种子,并且通过取余运算和除以整数100来确定随机数的范围。
另外还需引用以下头文件:
#include
#include
4.2算法的时空分析
(1)时间复杂度:
Floyed函数T(n)=O(n2+n3)
(2)空间复杂度:
本程序的空间复杂度均为S(n)=(n2);即存放n2个节点数据辅助空间。
4.3经验和体会
(1)c语言的学习实践很重要。
自学习C语言以来,我们就没怎么练习上机实践能力,所以对于代码的敏感度不够,一个错误出现了,不是很容易发现。
在这次课程设计中,我就犯了很多高手认为很基础的错误,比如说:
printf函数的用法,变量声明的位置,还有就是指针数组的用法。
犯错误是不可避免的,但是我们要认真地去发现错误和修改错误。
我在运行后,知道自己的程序有错误,我首先一步一步慢慢看,慢慢分析,在整个程序中找不出来就将该部分分离出去进行测试,这样,就很容易找到问题所在了。
(2)编写c语言程序必须要细心,特别注意标点符号的书写。
同一个error可能要改个几遍才能改好,由于平时编程经历少的缘故,总感觉有些吃力,要解决这一问题就要自己找题目练习,而不是仅仅依赖于老师每次实验和考试。
另外通过程序的编写还发现自己在c语言编程方面存在不足,要继续加强练习。
(3)要善于利用身边的资源。
资源既包括网络资源也包括人力资源。
遇到一个问题先要通过网络查找解决办法,如果还是不能解决就要学会请教别人,毕竟身边有很多技术牛人和学长学姐,他们都给我很耐心地解答,让我很感动的同时也受益匪浅。
(4)通过这次课设对弗洛伊德