最便宜航空路线求解文档格式.docx
《最便宜航空路线求解文档格式.docx》由会员分享,可在线阅读,更多相关《最便宜航空路线求解文档格式.docx(39页珍藏版)》请在冰豆网上搜索。
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)在每一个功能执行完后,都会提示继续执行还是返回主菜单。
箭头流程
武汉
北京
长沙
厦门
上海
郑州
广州
深圳
天津
大连
1584
1219
2611
1006
743
1573
612
1130
1461
1903
2346
1575
1.5无向带权费用图
2.概要设计
2.1抽象数据类型定义
本程序运用了关于图这种数据结构,它的抽象数据类型定义如下:
typedefstructunDiGraph
{
intnumVerts;
//结点
costAdjcost;
//邻接矩阵
}unDiGraph,*UNG;
基本操作:
unDiGraph*CreateCostG()
操作结果:
构造带权(费用)图。
PathMat*Floyed(unDiGraph*D)
操作结果:
Floyed函数
求任意两点的最短路径。
2.2主程序流程及各程序模块之间的层次(调用)关系
Main函数
输出方式1
f_money1()
pri()
查看城市
输出方式3
f_money3()
输出方式2
f_money2()
退出程序
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<
stdio.h>
stdlib.h>
time.h>
//需引用的头文件
#defineINF65535//定义一个最大数为无穷值,表示两城市之间无直飞航班
#defineMAX23
typedefintcostAdj[MAX+1][MAX+1];
//图邻接矩阵从1开始记数
intPath[MAX+1][MAX+1];
//图的定义
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()输出城市
Print城市代码
1=>
i
Whilei<
=c_number
Printi
调用pr()函数
}
(3)unDiGraph*CreateCostF(into)飞机花费的存贮功能
Begin
a,0=>
b,1=>
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
c_number+1
Whilej<
INF=>
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<
c_number+1;
j++)
{
Wuhan[j-1]=>
cost[j][1]
Beijing[j-1]=>
cost[j][2]
Xiamen[j-1]=>
cost[j][3]
Guangzhou[j-1]=>
cost[j][4]
Dalian[j-1]=>
cost[j][5]
Shanghai[j-1]=>
cost[j][6]
Changsha[j-1]=>
cost[j][7]
Shenzhen[j-1]=>
cost[j][8]
Zhengzhou[j-1]=>
cost[j][9]
Tianjin[j-1]=>
cost[j][10]
}
return(G);
(4)Floyed(unDiGraph*D,unDiGraph*M)函数Floyed函数求任意两点的最短路径
c_number=>
n
while(i<
=n)
1=>
j
while(j<
=n)
{
D->
cost[i][j]=>
A[i][j]初始化矩阵A。
M->
C[i][j]
-1=>
Path[i][j]初始化矩阵p,置-1.
}
}
for(0=>
k;
k<
=n;
k++)为逐步加入的中间结点
{
i;
i<
i++)i为A中行号
for(0=>
if(A[i][k]+A[k][j]<
A[i][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{
B[i][j]
}
print最短路径为:
(5)prn_pass(inti,intj)输出最短路径所经过的点
Begin
If(Path[i][j]!
=-1)
递归调用prn_pass(i,Path[i][j])
调用pr(Path[i][j],0)
(6)f_money1()输出方式1函数
Begin
l
do{
Print始发地可直飞目的地
Print北京广州武汉
Print长沙大连天津
Print大连长沙厦门郑州
Print广州北京上海郑州
Print上海广州深圳天津
Print深圳上海天津
Print天津长沙上海深圳
Print武汉北京厦门
Print厦门大连武汉
Print郑州长沙广州
Print1.继续输出所有城市名以及每一城市所有可直飞到达的城市列表2.返回主菜单清选择...
inputl输入1或2选择是否继续。
1=>
(7)f_money2()输出方式2函数
Bcity,Ecity//起始成市号码和终点城市号码
money[4]
i,j
s,w
discount[4]
while(h==1)
print请输入起始城市和目的城市的代码,中间以空格隔开,范围(1--%d,c_number
inputBcity
inputEcity输入起始城市和终点城市的代码。
if(!
((0<
Bcity&
&
Bcity<
c_number+1)&
(0<
Ecity&
Ecity<
Bcity!
=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=>
4;
{
i<
100;
i++)
if(!
(i%10))
rand()%80+20=>
w
w/100=>
s
break;
}
s=>
discount[j]
}
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清选择...
(8)f_money3()输出方式3函数
Bcity,Ecity起始成市号码和终点城市号码
L
money
M
month
quarter
do{
Print"
请输入月份(请在1-12之间选择):
"
Inputmonth
if(month>
=12||month<
=1)
输入出错!
\n"
exit
(1);
pri()输出城市列表及相应代码。
if(!
{
Print\n出错啦!
\n"
输入出错
exit
(1)关闭所有文件,终止正在执行的程序
}
Floyed(CreateCostF(0))调用Floyed函数。
if(B[Bcity][Ecity]>
5000)
{
print无航班\n"
else{
srand((unsigned)time(NULL随机种子
if(1<
=month<
=3)
discount[0]=>
m
1=>
quarter
Print"
你选择的是%d月,位于第%d季度,折扣是%.2lf\n"
month,quarter,m
elseif(4<
=6)
discount[1]=>
2=>
elseif(7<
=9)
discount[2]=>
3=>
elseif(10<
=12)
discount[3]=>
4=>
(float)m*B[Bcity][Ecity]=>
money
最佳线路:
合计:
%.lf\n"
money
Print1.继续输入月份、起始城市和目的城市名称,输出最佳方案\n2.返回主菜单\n清选择...
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<
4.2算法的时空分析
(1)时间复杂度:
Floyed函数T(n)=O(n2+n3)
(2)空间复杂度:
本程序的空间复杂度均为S(n)=(n2);
即存放n2个节点数据辅助空间。
4.3经验和体会
(1)c语言的学习实践很重要。
自学习C语言以来,我们就没怎么练习上机实践能力,所以对于代码的敏感度不够,一个错误出现了,不是很容易发现。
在这次课程设计中,我就犯了很多高手认为很基础的错误,比如说:
printf函数的用法,变量声明的位置,还有就是指针数组的用法。
犯错误是不可避免的,但是我们要认真地去发现错误和修改错误。
我在运行后,知道自己的程序有错误,我首先一步一步慢慢看,慢慢分析,在整个程序中找不出来就将该部分分离出去进行测试,这样,就很容易找到问题所在了。
(2)编写c语言程序必须要细心,特别注意标点符号的书写。
同一个error可能要改个几遍才能改好,由于平时编程经历少的缘故,总感觉有些吃力,