地铁线路查询(easyx)

问题描述:

当一个用户从甲地到乙地时,由于不同需求,就有不同的交通路线,有人希望以最短距离到达,有人希望用最少的换乘次数等。请编写一北京地铁线路查询系统,通过输入起始站、终点站,为用户提供两种或以上决策的交通咨询。

设计要求:

  1. 提供对地铁线路进行编辑的功能,要求可以添加或删除线路
  2. 提供多种决策:最短距离,最短时间,最少换乘次数等。
  3. 中途不考虑等候,拥堵等消耗时间。
  4. 该系统以人机对话方式进行。用户输入起始站,终点站以及需求原则(需求原则包括最短距离,最短时间,最少换乘次数),系统输出乘车方案:乘几号线,距离,时间,费用,换乘方法等相关信息。

效果图如下:

源码+地铁信息txt文件见github:https://github.com/piedpiperG/Beijing-Subway.git

目录

一,使用的数据结构

1.采用邻接表为存储结构

2.其它数据结构

二,程序中使用的算法和重要函数

1.最短路径算法

2.数据的录入与邻接表初始化

 3.easyx展示输出路线

 三,地铁线路系统的设计与实现

1.最初构想

 2.图的构建

3. 寻找最短路程方案与最短时间方案

4.寻找最少换乘方案

5.站点的删除

6.新增线路

7.easyx界面设计

 四,工作流程与案例实例展示

五,总结与不足

六,程序源码如下


一,使用的数据结构

1.采用邻接表为存储结构

用struct封装站点和道路信息

每一个站点为邻接表的顶点,通过函数,查找出两个站点间道路的长度和所用时间

struct Stations
{
	string name;	//站点名称
	string belongs[20];//所属线路(换乘站的话属于多条线路)
	Stations* nextStaion;//指向下一站的指针(换乘站可能有多个下一站)
}station[500];

struct Roads
{
	bool ifuse = true;
	string	from;	//从哪里来
	string	to;		//到哪里去
	string  belong;	//所属线路
	double	distance;	//道路长度
	double	equaltime;	//所用时间
}road[5000];

2.其它数据结构

封装输出信息,在屏幕上打印出路径途径站点与时间,距离,花费

封装每条线路的名称和距离

struct Outans
{
	vector<string>disans;	//最短路程结果数组
	vector<string>timans;	//最短时间结果数组
	int	Odistance;			//最短路程距离
	int distime;			//最短路程时间
	double Otime;			//最短时间时间
	int timdist;			//最短时间距离
	int	Dcostmoney;			//最短路程花费
	int Tcostmoney;			//最短时间花费
}outans,outans2;

struct Sublines
{
	string	name;
	int		speed;
}subline[35];

二,程序中使用的算法和重要函数

1.最短路径算法

在查找最短路时使用dijsktra算法

思想为维护vector<int>vist,vector<int>dist,vector<int>line三个数组得出结果

vist用来记录是否访问了第i个结点

dist用来存储第i个结点到起始点的当前最短距离,初始全设置为INT_MAX

line用来记录按照路径第i个结点上一个结点是什么

循环遍历各个结点,每次取出到起点距离最短且未被vist标记的点,而后通过邻接表更新其它各个点到起始点的最短距离,直到终点也被vist标记时,结束遍历。

此时dist[end]就是最短距离

回溯line[end]即可得出从起始点到终点的最短路径

void	dijkstra(string start, string end)
{
	//最短路径算法辅助数组
	vector<int>Dvis(Stationnum);//标记访问数组
	vector<int>Ddis(Stationnum);//标记起始点到每一个端点最短路径数组
	vector<double>Dtim(Stationnum);//记录最短时间
	vector<int>Dlin(Stationnum);//记录当前结点上一个结点是什么
	vector<string>Dans;//输出路线结果
	for (int i = 1; i < Stationnum; i++)	//对数组进行初始化
	{
		Ddis[i] = INT_MAX;
	}
	Ddis[findStation(start)] = 0;	//初始化出发结点
	Dtim[findStation(start)] = 0;
	while (Dvis[findStation(end)] != 1)	//当终点没有被标记时,持续循环
	{
		int	cur = Ddismin(Ddis, Dvis);	//找到当前到起点最短的路径
		Stations* sta = station[cur].nextStaion;
		while (sta)	//更新该结点到其它结点的距离
		{
			int nex = findStation(sta->name);
			if (Ddis[nex] > Ddis[cur] + road[findRoad(station[cur].name, station[nex].name)].distance)
			{
				Ddis[nex] = Ddis[cur] + road[findRoad(station[cur].name, station[nex].name)].distance;
				Dtim[nex] = Dtim[cur] + road[findRoad(station[cur].name, station[nex].name)].equaltime;
				Dlin[nex] = cur;
			}
			sta = sta->nextStaion;
		}
		Dvis[cur] = 1;
	}
	int	temp = findStation(end);
	while (temp != findStation(start))
	{
		Dans.push_back(station[temp].name);
		temp = Dlin[temp];
	}
	//Dans.insert(Dans.begin(), start);
	Dans.push_back(start);
	string	linenote = station[findStation(Dans[0])].belongs[0];
	outans.disans = Dans;
	outans.Odistance = Ddis[findStation(end)];
	outans.distime = Dtim[findStation(end)];
	double tempdis = (double)outans.Odistance / 1000;
	outans.Dcostmoney = calculatemoney(tempdis);
	for (int i = 0; i < Dans.size(); i++)
	{
		
		cout << Dans[Dans.size() - i - 1] << "->";
	}
	cout << endl;
	cout << "距离优先:" << endl;
	cout << "最短距离为:" << Ddis[findStation(end)] << endl;
	cout << "花费时间为:" << Dtim[findStation(end)] << endl;
	cout << "所需花费为:" << outans.Dcostmoney << endl;
}

2.数据的录入与邻接表初始化

根据北京地铁官网给出的各个站点之间间距如下图:

故选择将此表复制粘贴到本地为txt文件

 然后用fstream库中的函数将文本数据以行为单位,进行录入,然后使用函数istringstream将每一行的三个字符串拆开,依次初始化站点和距离长度。

运用链表插入的知识构建邻接表。

void	readfile1()
{
	//1、包含头文件
	//2、创建流对象
	ifstream ifs;
	//3、打开文件并且判断是否打开成功
	ifs.open("D:\\学校事务\\数据结构与算法课程设计\\地铁2.txt", ios::in);
	if (!ifs.is_open())
	{
		cout << "文件打开失败" << endl;
		return;
	}
	//存储数据用到的中介值
	string	linename;//线路名称
	int		cnt1 = 1;//车站编号
	int		cnt2 = 1;//道路编号
	int		formStation;//前车站编号
	int		lateStation;//后车编号
	//4、读数据
	string buf;
	while (getline(ifs, buf))	//对每一行的处理
	{
		//cout << buf << endl;
		if (buf[0] == '#')	//当这一行是线路时,只存储线路
		{
			linename = buf;
			continue;
		}
		istringstream is(buf);    //将is绑定到buf
		string s;
		int	tempcnt = 1;
		while (is >> s)
		{
			if (tempcnt == 1)	//第一个字符串
			{
				if (findStation(s) == -1)	//没有存储这个站点
				{
					station[cnt1].name = s;
					int i = 0;
					while (station[cnt1].belongs[i] != "")
						i++;
					station[cnt1].belongs[i] = linename;
					formStation = cnt1;
					cnt1++;
				}
				else
				{
					int	j = findStation(s);
					int	i = 0;
					while (station[j].belongs[i] != "")
						i++;
					station[j].belongs[i] = linename;
					formStation = j;
				}
				tempcnt = 2;
			}
			else if (tempcnt == 2)
			{
				int j = cnt1;
				bool	ok = false;
				if (findStation(s) == -1)	//没有存储这个站点
				{
					station[cnt1].name = s;
					ok = true;
				}
				else
				{
					j = findStation(s);
				}
				int i = 0;
				while (station[j].belongs[i] != "")
					i++;
				station[j].belongs[i] = linename;	//添加所属线路
				insertStation(formStation, j);//插入前一个结点的邻接表
				insertStation(j, formStation);
				lateStation = j;	//记录后车编号
				if (ok)
					cnt1++;
				tempcnt = 3;
			}
			else if (tempcnt == 3)
			{
				if (findRoad(station[formStation].name, station[lateStation].name) == -1)
				{
					road[cnt2].from = station[formStation].name;
					road[cnt2].to = station[lateStation].name;
					road[cnt2].distance = atoi(s.c_str());
					//road[cnt2].equaltime = road[cnt2].distance / findspeed(findbelong(station[formStation].name, station[lateStation].name));
					cnt2++;
					road[cnt2].to = station[formStation].name;
					road[cnt2].from = station[lateStation].name;
					road[cnt2].distance = atoi(s.c_str());
					//road[cnt2].equaltime = road[cnt2].distance / findspeed(findbelong(station[formStation].name, station[lateStation].name));
					cnt2++;
				}
				tempcnt = 1;
			}
			//cout << s << endl;
		}

	}
	//5、关闭文件
	ifs.close();
}

 3.easyx展示输出路线

如何将已经录入的信息通过easyx展示在屏幕上是一个完全自己通过几个函数摸索出来的东西。

这里主要讲述如何将已经查找到的路径工整打印在屏幕上。

难点1:文字在背景图片的干扰下看不清

解决方法:在文字背后先画出彩色方框,来衬托文字的存在

难点2:easyx中的输出函数outtextxy只能将文字按照坐标打印在屏幕上,如何确保各个字符串有序排列,不重叠,不超出屏幕。

解决方法:设置变量对坐标进行处理,根据每一个字符串的长度来调整横纵坐标的情况,在将要超出屏幕宽度时控制纵坐标参数达到自动换行

难点3:距离优先,时间优先多种选择方式如何展示

解决方法:设置翻页功能,展示不下就在下一页展示

void display()
{
	int	lengthcnt = 2;//纵向列数
	int lengthlim=35;//纵向单位
	//int	widthcnt = 0;//横向行数
	int	widthlim = 6;//横向单位
	int width = 0;
	bool stopsignal = false;//停止打印最短路路径标志
	while (!stopsignal)
	{
		string templine = "";
		for (int i = outans.disans.size()-1; i >= 0; i--)
		{
			if (width > 900)
			{
				lengthcnt++;
				width = 0;
			}
			if (i == outans.disans.size() - 1)
			{
				templine = findbelong(outans.disans[i], outans.disans[i - 1]);
				lengthcnt++;
				setbkmode(TRANSPARENT);
				setfillcolor(LIGHTRED);
				int	strlength = templine.size();
				fillroundrect(20, lengthlim * lengthcnt, 20 + strlength * 15, lengthlim * lengthcnt + 25, 10, 10);
				settextstyle(25, 0, "黑体");
				setbkmode(TRANSPARENT);
				settextcolor(WHITE);
				outtextxy(20, lengthlim * lengthcnt, templine.c_str());
				lengthcnt++;
				//widthcnt = 0;
			}	//输出打印几号线

			
			setbkmode(TRANSPARENT);
			setfillcolor(LIGHTBLUE);
			int	strlength = outans.disans[i].size();
			fillroundrect(width, lengthlim * lengthcnt, width + 13 * strlength, lengthlim * lengthcnt + 25, 10, 10);
			settextstyle(25, 0, "楷体");
			setbkmode(TRANSPARENT);
			settextcolor(YELLOW);
			outtextxy(width , lengthlim * lengthcnt, outans.disans[i].c_str());
			width += 13 * strlength + widthlim;
			//widthcnt++;

			if (i > 0 && findbelong(outans.disans[i], outans.disans[i - 1]) != templine)
			{
				templine = findbelong(outans.disans[i], outans.disans[i - 1]);
				lengthcnt++;
				setbkmode(TRANSPARENT);
				setfillcolor(LIGHTRED);
				int	strlength1 = templine.size();
				fillroundrect(20, lengthlim * lengthcnt, 20 + strlength1 * 15, lengthlim * lengthcnt + 25, 10, 10);
				settextstyle(25, 0, "黑体");
				setbkmode(TRANSPARENT);
				settextcolor(WHITE);
				outtextxy(20, lengthlim * lengthcnt, templine.c_str());
				lengthcnt++;
				//widthcnt = 0;
				width = 0;


				setbkmode(TRANSPARENT);
				setfillcolor(LIGHTBLUE);
				int	strlength = outans.disans[i].size();
				fillroundrect(width + 0, lengthlim * lengthcnt, width + 0 + 13 * strlength, lengthlim * lengthcnt + 25, 10, 10);
				settextstyle(25, 0, "楷体");
				setbkmode(TRANSPARENT);
				settextcolor(YELLOW);
				outtextxy(width + 0, lengthlim * lengthcnt, outans.disans[i].c_str());
				//widthcnt++;
				width += strlength * 13 + widthlim;
			}	//输出打印几号线

		}
		stopsignal = true;
	}
	setbkmode(TRANSPARENT);
	setfillcolor(WHITE);
	fillroundrect(700, 10, 700 + 300, 10 + 25, 10, 10);
	settextstyle(25, 0, "隶书");
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(700, 10, "总距离:");
	char grade[100] = "";
	sprintf(grade, "%d", outans.Odistance);
	outtextxy(800, 10, grade);

	setbkmode(TRANSPARENT);
	setfillcolor(WHITE);
	fillroundrect(700, 40, 700 + 300, 40 + 25, 10, 10);
	settextstyle(25, 0, "隶书");
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(700, 40, "预计时间:");
	char grade1[100] = "";
	sprintf(grade1, "%d", outans.distime);
	outtextxy(825, 40, grade1);

	setbkmode(TRANSPARENT);
	setfillcolor(WHITE);
	fillroundrect(700, 70, 700 + 300, 70 + 25, 10, 10);
	settextstyle(25, 0, "隶书");
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(700, 70, "预计花费:");
	char grade2[100] = "";
	sprintf(grade2, "%d", outans.Dcostmoney);
	outtextxy(825, 70, grade2);

	setbkmode(TRANSPARENT);
	setfillcolor(YELLOW);
	fillroundrect(200, 50, 200 + 210, 50 + 35, 10, 10);
	settextstyle(35, 0, "宋体");
	setbkmode(TRANSPARENT);
	settextcolor(CYAN);
	outtextxy(200, 50, "最短距离策略");


	/*setbkmode(TRANSPARENT);
	setfillcolor(LIGHTBLUE);
	fillroundrect(10, 100, 10 + 75, 100 + 25, 10, 10);
	settextstyle(25, 0, "楷体");
	setbkmode(TRANSPARENT);
	settextcolor(YELLOW);
	outtextxy(10, 100, "西直门");*/
}

 三,地铁线路系统的设计与实现

1.最初构想

考虑到如此庞大的数据量,邻接矩阵不再适用,很快确定了把邻接表作为存储结构

构建结点时,考虑要不要把普通站设为一种结点,始发站设为一种结点,终点站再设为一种结点,然而这样一来太过复杂,在后序的算法中一个查找就需要好几种数据结构。所以想到干脆一种数据结构,但要尽可能详尽包含所有的信息,所以便设计了Stations和Roads两种完备的数据结构。

看似有些臃肿,但实则方便,后序的所有功能都可以通过另写函数来实现,如我们虽然没有标记哪一站是换乘站,但知道每一站的所属线路,写一个哈希函数就可以找出相邻两站共同的所属线路从而确认是否换乘。

数据存储部分:

struct Stations
{
	string name;	//站点名称
	string belongs[20];//所属线路(换乘站的话属于多条线路)
	Stations* nextStaion;//指向下一站的指针(换乘站可能有多个下一站)
}station[500];
struct Roads
{
	bool ifuse = true;
	string	from;	//从哪里来
	string	to;		//到哪里去
	string  belong;	//所属线路
	double	distance;	//道路长度
	double	equaltime;	//所用时间
}road[5000];
struct Sublines
{
	string	name;
	int		speed;
}subline[35];

 2.图的构建

通过链表的插入知识和文件读取很轻松的构建了整个地铁网络图,只要确定好了存储的数据结构,在图的构建上并不困难

3. 寻找最短路程方案与最短时间方案

 刚开始的想法是写一个bfs或dfs搜索,将起点到终点所有可能的路线搜出来,然后想比较什么比较什么不就可以了,一个bfs函数很快写好了,但由于北京地铁庞大的数据量,稍微远一点的距离往往需要长达4,5分钟才能得出结果... ...遂放弃

而后采用效率高得多的最短路径算法dijkstra,最短时间就是将原本的最短路径参数除以速度,所以两个方案共用同一种函数即可。

4.寻找最少换乘方案

最少换乘本质上也用的是dijkstra算法,只不过是单源最短路径。

如果两个站点在一条线路上,那么就将两个站点之间的距离设为1,否则设为9999,这样搜出来的路径就是最少换乘要达到的路径了

这里另开辟了一个邻接矩阵来初始化新的数据

//计算最少换乘用图
vector<vector<int>>Map(Stationnum, vector<int>(Stationnum));

void initMap()
{
	for (int i = 1; i < Stationnum; i++)
	{
		for (int j = 1; j < Stationnum; j++)
		{
			if (findbelong(station[i].name, station[j].name) != "")
			{
				Map[i][j] = 1;
			}
			else
			{
				Map[i][j] = 9999;
			}
		}
	}
}

5.站点的删除

因为各个站点之间是依靠邻接表指针相联系的,所以站点的删除上我们直接让站点的指针指向空,表示此路不通即可

void forbiddenstation(string name)
{
	int cur = findStation(name);
	Stations* sta = station[cur].nextStaion;
	while (sta)
	{
		int nex = findRoad(station[cur].name, sta->name);
		road[nex].ifuse = false;
		sta = sta->nextStaion;
	}
	station[0].nextStaion = emptystation.nextStaion;
	station[cur].nextStaion = station[0].nextStaion;

}

6.新增线路

新增线路的函数内容来源于初始化数据的readfile1,原理相同,就是把从txt文件中读取数据,变成了手动输入数据,而后新增节点存储在图中。

void insertroad(string start, string end, string length)
{
	if (findStation(end) == -1)	//没有存储这个站点
	{
		station[insistnum].name = end;
		insistnum++;
	}
	int s = findStation(start);
	int e = findStation(end);
	insertStation(s, e);//插入前一个结点的邻接表
	insertStation(e, s);

	road[staynum].from = start;
	road[staynum].to = end;
	road[staynum].distance = atoi(length.c_str());
	//road[cnt2].equaltime = road[cnt2].distance / findspeed(findbelong(station[formStation].name, station[lateStation].name));
	staynum++;
	road[staynum].to = start;
	road[staynum].from = end;
	road[staynum].distance = atoi(length.c_str());
	//road[cnt2].equaltime = road[cnt2].distance / findspeed(findbelong(station[formStation].name, station[lateStation].name));
	staynum++;


}

7.easyx界面设计

简单了解了easyx的几个函数和使用方法,通过向easyx写出的贪吃蛇小游戏原理学习,制作出了这个简易的easyx界面。

首先在背景贴上背景图

而后其它的动画文字都是在不断地刷新的,在一个while(true)循环中

所以我们加入一个Mode的判断量

通过if(Mode)的方式,就可以实现界面跳转的功能。

而后使用函数判断按键与鼠标是否参与,就制作出了一个简单风格的页面。

部分实现代码:

while (1)
	{
		BeginBatchDraw(); //缓冲区打印,防止闪屏
		cleardevice();//刷新
		putimage(0, 0, &background);//绘制图像到屏幕,图片左上角坐标为(0,0)

		while (_kbhit())//如果有按键则进入,否则不进入循环
		{
			char userkey = 0;
			userkey = _getch();
			if (userkey == VK_ESCAPE)
			{
				Mode = 0;
			}
		}

		if (Mode == 0)
		{
			TCHAR s[50] = "1.查找线路";
			TCHAR s1[50] = "2.关停站点";
			TCHAR s2[50] = "3.关停线路";
			TCHAR s3[50] = "4.插入路线";
			button(391, 200, 170, 50, s);
			button(391, 300, 170, 50, s1);
			button(391, 400, 170, 50, s2);
			button(391, 500, 170, 50, s3);
			ExMessage msg;
			if (peekmessage(&msg, EM_MOUSE))
			{
				switch (msg.message)
				{
				case WM_LBUTTONDOWN:
					if (msg.x >= 391 && msg.x <= 391 + 170 && msg.y >= 200 && msg.y <= 200 + 50)
					{
						cout << "!" << endl;
						Mode = 1;
						//在此处写下按钮点击时要执行的函数,实现相应的功能
					}
					if (msg.x >= 391 && msg.x <= 391 + 170 && msg.y >= 300 && msg.y <= 300 + 50)
					{
						cout << "?" << endl;
						Mode = 2;
						//在此处写下按钮点击时要执行的函数,实现相应的功能  
					}
					if (msg.x >= 391 && msg.x <= 391 + 170 && msg.y >= 400 && msg.y <= 400 + 50)
					{
						cout << "@" << endl;
						Mode = 3;
						//在此处写下按钮点击时要执行的函数,实现相应的功能
					}
					if (msg.x >= 391 && msg.x <= 391 + 170 && msg.y >= 500 && msg.y <= 500 + 50)
					{
						cout << "&" << endl;
						Mode = 4;
						//在此处写下按钮点击时要执行的函数,实现相应的功能
					}
					break;
				default:
					break;
				}
			}
			
		}

 四,工作流程与案例实例展示

运行程序,进入界面菜单:

输入你想搜索的最短线路,结果会在旁边显示,如果输入不正确,会弹窗提示

点击确认,得到结果,通过右下角的上下翻页键查看不同的策略方案

而后三个功能和此功能有着相同的界面和使用方法

需要注意的是,在添加路线功能中不允许添加一条独立的路线,起始站点必须是地图中已有的站点,终点站可以是自己新建的站点。 

五,总结与不足

此次大作业第一眼看起来任务量很大且难度很大,但分模块操作起来发现过程比想象的容易得多,并且对于基础数据结构和算法较为熟练运用后,大的问题拆分成小的函数逐个解决即可。自己摸索easyx的过程很有趣,做出来的页面虽然看起来像上个世纪的东西但仍然会给我惊喜。由于受时间所限,还有很多没有完善的地方,比如最少换乘方案还没有给出完备的过程和距离时间,界面如果不采用画图,自己做贴画按钮一定更好看,想加一个鼠标移动到按钮上方出现的特效来不及了。总体来说大致的功能完成的还是不错的,暴露出规划不明确,函数乱写,到后来开摆式的复制粘贴等问题都是不错的经验。

六,程序源码如下

head.h

#include<iostream>
#include<stdlib.h>
#include<string>
#include<fstream>
#include <sstream>    //使用istringstream所需要的头文件 
#include <cassert>
#include<queue>
#include<vector>
#include<time.h>
#include<graphics.h>
#include<conio.h>
#include<easyx.h>
#include<windows.h>
#include<mmsystem.h>
#include <unordered_map>
using	namespace std;
/*采用邻接表作为存储结构
	构建站点Station和道路Road两种结构体*/
	//站点结构体如下:
int	Stationnum = 356;
int insistnum = 352;
struct Stations
{
	string name;	//站点名称
	string belongs[20];//所属线路(换乘站的话属于多条线路)
	Stations* nextStaion;//指向下一站的指针(换乘站可能有多个下一站)
}station[500];
Stations emptystation;

//计算最少换乘用图
vector<vector<int>>Map(Stationnum, vector<int>(Stationnum));

//道路结构体如下:
int	Roadnum = 800;
int staynum = 796;
struct Roads
{
	bool ifuse = true;
	string	from;	//从哪里来
	string	to;		//到哪里去
	string  belong;	//所属线路
	double	distance;	//道路长度
	double	equaltime;	//所用时间
}road[5000];

int	Sublinenum = 30;
//记录各条线路速度
struct Sublines
{
	string	name;
	int		speed;
}subline[35];

//记录搜索时的方式
struct pos
{
	string	Loc;	//所在位置
	int	Distance;//行程距离
	int	Changetime;//换乘次数
	int	Costtime;//花费时间
	vector<string>Rember;//记录途径地点
};

//存储结果的结构体
struct Outans
{
	vector<string>disans;	//最短路程结果数组
	vector<string>timans;	//最短时间结果数组
	int	Odistance;			//最短路程距离
	int distime;			//最短路程时间
	double Otime;			//最短时间时间
	int timdist;			//最短时间距离
	int	Dcostmoney;			//最短路程花费
	int Tcostmoney;			//最短时间花费
}outans,outans2;




//初始化邻接表和道路
void	readfile1();
//初始化各个线路的速度和时间
void	readfile2();
//寻找到车站的编号
int findStation(string str);
//寻找到道路的编号
int	findRoad(string start, string end);
//构建邻接表,插入结点
void insertStation(int start, int end);
//打印邻接表
void print1();
//打印道路
void print2();
//深搜给出解决方案
void bfs(string start, string end);
//最短路径搜索
void dijkstra(string start, string end);
//最短时间搜索
void dijkstra2(string start, string end);
//最少换乘搜索
void dijkstra3(string start, string end);
//最短路函数种搜索距离最小点函数
int	Ddismin(vector<int>arr, vector<int>brr);
int	Ddismin2(vector<double>arr, vector<int>brr);
//返回线路对应的速度
double	findspeed(string str);
//返回道路所属的线路
string findbelong(string start, string end);
//最少换乘路线
void dfs(string start, string end);
//easyx按键
void button(int x, int y, int w, int h, TCHAR* text);
//展示优先路程路径
void display();
//展示优先时间路径
void display2();
//展示最少换乘路径
void display3();
//计算里程花费的钱
int calculatemoney(double n);
//弹出错误
bool showerror(string name);
//停用站点
void forbiddenstation(string name);
//停用线路
void forbiddenroad(string name);
//初始化Map
void initMap();
//添加线路
void insertroad(string start, string end, string length);

function1.h

#include"head.h"

void	readfile1()
{
	//1、包含头文件
	//2、创建流对象
	ifstream ifs;
	//3、打开文件并且判断是否打开成功
	ifs.open("./resource/地铁2.txt", ios::in);
	if (!ifs.is_open())
	{
		cout << "文件打开失败" << endl;
		return;
	}
	//存储数据用到的中介值
	string	linename;//线路名称
	int		cnt1 = 1;//车站编号
	int		cnt2 = 1;//道路编号
	int		formStation;//前车站编号
	int		lateStation;//后车编号
	//4、读数据
	string buf;
	while (getline(ifs, buf))	//对每一行的处理
	{
		//cout << buf << endl;
		if (buf[0] == '#')	//当这一行是线路时,只存储线路
		{
			linename = buf;
			continue;
		}
		istringstream is(buf);    //将is绑定到buf
		string s;
		int	tempcnt = 1;
		while (is >> s)
		{
			if (tempcnt == 1)	//第一个字符串
			{
				if (findStation(s) == -1)	//没有存储这个站点
				{
					station[cnt1].name = s;
					int i = 0;
					while (station[cnt1].belongs[i] != "")
						i++;
					station[cnt1].belongs[i] = linename;
					formStation = cnt1;
					cnt1++;
				}
				else
				{
					int	j = findStation(s);
					int	i = 0;
					while (station[j].belongs[i] != "")
						i++;
					station[j].belongs[i] = linename;
					formStation = j;
				}
				tempcnt = 2;
			}
			else if (tempcnt == 2)
			{
				int j = cnt1;
				bool	ok = false;
				if (findStation(s) == -1)	//没有存储这个站点
				{
					station[cnt1].name = s;
					ok = true;
				}
				else
				{
					j = findStation(s);
				}
				int i = 0;
				while (station[j].belongs[i] != "")
					i++;
				station[j].belongs[i] = linename;	//添加所属线路
				insertStation(formStation, j);//插入前一个结点的邻接表
				insertStation(j, formStation);
				lateStation = j;	//记录后车编号
				if (ok)
					cnt1++;
				tempcnt = 3;
			}
			else if (tempcnt == 3)
			{
				if (findRoad(station[formStation].name, station[lateStation].name) == -1)
				{
					road[cnt2].from = station[formStation].name;
					road[cnt2].to = station[lateStation].name;
					road[cnt2].distance = atoi(s.c_str());
					//road[cnt2].equaltime = road[cnt2].distance / findspeed(findbelong(station[formStation].name, station[lateStation].name));
					cnt2++;
					road[cnt2].to = station[formStation].name;
					road[cnt2].from = station[lateStation].name;
					road[cnt2].distance = atoi(s.c_str());
					//road[cnt2].equaltime = road[cnt2].distance / findspeed(findbelong(station[formStation].name, station[lateStation].name));
					cnt2++;
				}
				tempcnt = 1;
			}
			//cout << s << endl;
		}

	}
	//5、关闭文件
	ifs.close();
}

void readfile2()

{
	//1、包含头文件
	//2、创建流对象
	ifstream ifs;
	//3、打开文件并且判断是否打开成功
	ifs.open("./resource/地铁平均速度1.txt", ios::in);
	if (!ifs.is_open())
	{
		cout << "文件打开失败" << endl;
		return;
	}
	//统计地铁编号
	int	cnt = 1;
	//4、读数据
	string buf;
	while (getline(ifs, buf))	//对每一行的处理
	{
		istringstream is(buf);    //将is绑定到buf
		string s;
		while (is >> s)
		{
			if (s[0] == '#')
				subline[cnt].name = s;
			else
			{
				subline[cnt].speed = atoi(s.c_str());
			}
		}
		cnt++;
	}
	//5、关闭文件
	ifs.close();
	for (int i = 1; i < Roadnum; i++)
	{
		road[i].equaltime = road[i].distance / findspeed(findbelong(road[i].from, road[i].to));
	}
}

int findStation(string str)
{
	for (int i = 1; i < Stationnum; i++)
	{
		if (station[i].name == str)
			return	i;
	}
	return	-1;	//当不存在此站点时
}

int	findRoad(string start, string end)
{
	for (int i = 1; i < Roadnum; i++)
	{
		if (road[i].from == start && road[i].to == end)
			return	i;
	}
	return	-1;	//当不存在这个道路时
}

void insertStation(int start, int end)
{
	if (station[start].nextStaion == NULL)
	{
		Stations* newsta = new Stations;
		newsta->name = station[end].name;
		station[start].nextStaion = newsta;
		newsta->nextStaion = NULL;
	}
	else
	{
		Stations* newsta = new Stations;
		newsta->name = station[end].name;
		newsta->nextStaion = station[start].nextStaion;
		station[start].nextStaion = newsta;	//!!!
	}
}

void print1()
{
	for (int i = 1; i <= Stationnum; i++)
	{
		cout << station[i].name;
		Stations* sta = station[i].nextStaion;
		while (sta)
		{
			cout << "->" << sta->name;
			sta = sta->nextStaion;
		}
		cout << endl;
	}
}

void print2()
{
	for (int i = 1; i <= Roadnum; i++)
	{
		cout << road[i].from << "->" << road[i].to << " need " << road[i].distance << "and" << road[i].equaltime << endl;
	}
}

void bfs(string start, string end)
{
	vector<int>vis(300);
	queue<pos>que;
	pos	cur;
	pos ans[2000];
	pos res;
	int	cnt = 1;
	cur.Loc = start;
	cur.Distance = 0;
	cur.Rember.push_back(start);
	vis[findStation(start)] = 1;
	que.push(cur);
	while (!que.empty())
	{
		cur = que.front();
		que.pop();
		if (cur.Loc == end)	//找到了目的地
		{
			ans[cnt] = cur;
			cnt++;
			break;
		}
		Stations* sta = station[findStation(cur.Loc)].nextStaion;
		while (sta)
		{
			pos nex;
			nex.Loc = sta->name;
			sta = sta->nextStaion;
			if (!vis[findStation(nex.Loc)])
			{
				nex.Distance = road[findRoad(cur.Loc, nex.Loc)].distance + cur.Distance;
				nex.Rember = cur.Rember;
				nex.Rember.push_back(nex.Loc);
				que.push(nex);
			}
		}
	}
	res.Distance = INT_MAX;
	for (int i = 1; i <= cnt - 1; i++)
	{
		if (ans[i].Distance < res.Distance)
			res = ans[i];
	}
	for (int i = 0; i < res.Rember.size(); i++)
		cout << res.Rember[i] << "->";
	cout << endl;
}

void	dijkstra(string start, string end)
{
	//最短路径算法辅助数组
	vector<int>Dvis(Stationnum);//标记访问数组
	vector<int>Ddis(Stationnum);//标记起始点到每一个端点最短路径数组
	vector<double>Dtim(Stationnum);//记录最短时间
	vector<int>Dlin(Stationnum);//记录当前结点上一个结点是什么
	vector<string>Dans;//输出路线结果
	for (int i = 1; i < Stationnum; i++)	//对数组进行初始化
	{
		Ddis[i] = INT_MAX;
	}
	Ddis[findStation(start)] = 0;	//初始化出发结点
	Dtim[findStation(start)] = 0;
	while (Dvis[findStation(end)] != 1)	//当终点没有被标记时,持续循环
	{
		int	cur = Ddismin(Ddis, Dvis);	//找到当前到起点最短的路径
		Stations* sta = station[cur].nextStaion;
		while (sta)	//更新该结点到其它结点的距离
		{
			int nex = findStation(sta->name);
			if (Ddis[nex] > Ddis[cur] + road[findRoad(station[cur].name, station[nex].name)].distance)
			{
				Ddis[nex] = Ddis[cur] + road[findRoad(station[cur].name, station[nex].name)].distance;
				Dtim[nex] = Dtim[cur] + road[findRoad(station[cur].name, station[nex].name)].equaltime;
				Dlin[nex] = cur;
			}
			sta = sta->nextStaion;
		}
		Dvis[cur] = 1;
	}
	int	temp = findStation(end);
	while (temp != findStation(start))
	{
		Dans.push_back(station[temp].name);
		temp = Dlin[temp];
	}
	//Dans.insert(Dans.begin(), start);
	Dans.push_back(start);
	string	linenote = station[findStation(Dans[0])].belongs[0];
	outans.disans = Dans;
	outans.Odistance = Ddis[findStation(end)];
	outans.distime = Dtim[findStation(end)];
	double tempdis = (double)outans.Odistance / 1000;
	outans.Dcostmoney = calculatemoney(tempdis);
	for (int i = 0; i < Dans.size(); i++)
	{

		cout << Dans[Dans.size() - i - 1] << "->";
	}
	cout << endl;
	cout << "距离优先:" << endl;
	cout << "最短距离为:" << Ddis[findStation(end)] << endl;
	cout << "花费时间为:" << Dtim[findStation(end)] << endl;
	cout << "所需花费为:" << outans.Dcostmoney << endl;
}

void dijkstra2(string start, string end)
{

	//最短路径算法辅助数组
	vector<int>Dvis(Stationnum);//标记访问数组
	vector<double>Ddis(Stationnum);//标记起始点到每一个端点最短路径数组
	vector<int>Dtim(Stationnum);
	vector<int>Dlin(Stationnum);//记录当前结点上一个结点是什么
	vector<string>Dans;//输出路线结果
	for (int i = 1; i < Stationnum; i++)	//对数组进行初始化
	{
		Ddis[i] = INT_MAX;
	}
	Ddis[findStation(start)] = 0;	//初始化出发结点
	Dtim[findStation(start)] = 0;
	while (Dvis[findStation(end)] != 1)	//当终点没有被标记时,持续循环
	{
		int	cur = Ddismin2(Ddis, Dvis);	//找到当前到起点最短的路径
		Stations* sta = station[cur].nextStaion;
		while (sta)	//更新该结点到其它结点的距离
		{
			int nex = findStation(sta->name);
			if (Ddis[nex] > Ddis[cur] + road[findRoad(station[cur].name, station[nex].name)].equaltime)
			{
				Ddis[nex] = Ddis[cur] + road[findRoad(station[cur].name, station[nex].name)].equaltime;
				Dtim[nex] = Dtim[cur] + road[findRoad(station[cur].name, station[nex].name)].distance;
				Dlin[nex] = cur;
			}
			sta = sta->nextStaion;
		}
		Dvis[cur] = 1;
	}
	int	temp = findStation(end);
	while (temp != findStation(start))
	{
		Dans.push_back(station[temp].name);
		temp = Dlin[temp];
	}
	//Dans.insert(Dans.begin(), start);
	Dans.push_back(start);
	string	linenote = station[findStation(Dans[0])].belongs[0];
	outans.timans = Dans;
	outans.Otime = Ddis[findStation(end)];
	outans.timdist = Dtim[findStation(end)];
	outans.Tcostmoney = calculatemoney(double(outans.timdist) / 1000);
	for (int i = 0; i < Dans.size(); i++)
	{

		cout << Dans[Dans.size() - i - 1] << "->";
	}
	cout << endl;
	cout << "时间优先:" << endl;
	cout << "所用距离为:" << Dtim[findStation(end)] << endl;
	cout << "最短时间为:" << Ddis[findStation(end)] << endl;
	cout << "所需花费为:" << outans.Tcostmoney << endl;
}

void dijkstra3(string start, string end)
{
	vector<int>vis(Stationnum);
	vector<int>dis(Stationnum);
	vector<int>lin(Stationnum);
	vector<string>ans;
	for (int i = 1; i < Stationnum; i++)
	{
		dis[i] = INT_MAX;
	}
	dis[findStation(start)] = 0;
	while (vis[findStation(end)] != 1)
	{
		int cur = Ddismin(dis, vis);
		for (int i = 1; i < Stationnum; i++)
		{
			int nex = i;
			if (dis[nex] > dis[cur] + Map[cur][nex])
			{
				dis[nex] = dis[cur] + Map[cur][nex];
				lin[nex] = cur;
			}
			vis[cur] = 1;
		}
	}
	int	temp = findStation(end);
	while (temp != findStation(start))
	{
		ans.push_back(station[temp].name);
		temp = lin[temp];
	}
	ans.push_back(start);
	outans2.timans = ans;




	for (int i = 0; i < ans.size(); i++)
	{
		cout << ans[ans.size() - i - 1] << "->";
	}
}


int	Ddismin(vector<int>arr, vector<int>brr)
{
	int	temp = INT_MAX;
	int	ans = 0;
	for (int i = 1; i < arr.size(); i++)
	{
		if (arr[i] < temp && brr[i] != 1)
		{
			temp = arr[i];
			ans = i;
		}
	}
	return	ans;
}
int	Ddismin2(vector<double>arr, vector<int>brr)
{
	int	temp = INT_MAX;
	int	ans = 0;
	for (int i = 1; i < arr.size(); i++)
	{
		if (arr[i] < temp && brr[i] != 1)
		{
			temp = arr[i];
			ans = i;
		}
	}
	return	ans;
}

double	findspeed(string str)
{
	for (int i = 1; i < Sublinenum; i++)
	{
		if (subline[i].name == str)
			return	subline[i].speed;
	}
	return	-1;
}

string findbelong(string start, string end)
{
	unordered_map<string, int>hash;
	int	cur = findStation(start);
	int	nex = findStation(end);
	for (int i = 0; i < 10; i++)
	{
		hash[station[cur].belongs[i]]++;
	}
	for (int i = 0; i < 10; i++)
	{
		if (hash[station[nex].belongs[i]] > 0)
		{
			return	station[nex].belongs[i];
		}
	}
	return "";
}

//void dfs()
//{
//
//}
int calculatemoney(double n)
{
	if (n <= 6)
		return	3;
	else if (n > 6 && n <= 12)
		return	4;
	else if (n > 12 && n <= 22)
		return	5;
	else if (n > 22 && n <= 32)
		return	6;
	else
	{
		return	(n - 32) / 20 + 1 + 6;
	}

}

void initMap()
{
	for (int i = 1; i < Stationnum; i++)
	{
		for (int j = 1; j < Stationnum; j++)
		{
			if (findbelong(station[i].name, station[j].name) != "")
			{
				Map[i][j] = 1;
			}
			else
			{
				Map[i][j] = 9999;
			}
		}
	}
	/*for (int i = 1; i < Stationnum; i++)
	{
		for (int j = 2; j < Stationnum; j++)
		{
			cout << Map[i][j] << " ";
		}
		cout << endl;
	}*/
}

void insertroad(string start, string end, string length)
{
	if (findStation(end) == -1)	//没有存储这个站点
	{
		station[insistnum].name = end;
		insistnum++;
	}
	int s = findStation(start);
	int e = findStation(end);
	insertStation(s, e);//插入前一个结点的邻接表
	insertStation(e, s);

	road[staynum].from = start;
	road[staynum].to = end;
	road[staynum].distance = atoi(length.c_str());
	//road[cnt2].equaltime = road[cnt2].distance / findspeed(findbelong(station[formStation].name, station[lateStation].name));
	staynum++;
	road[staynum].to = start;
	road[staynum].from = end;
	road[staynum].distance = atoi(length.c_str());
	//road[cnt2].equaltime = road[cnt2].distance / findspeed(findbelong(station[formStation].name, station[lateStation].name));
	staynum++;


}

void button(int x, int y, int w, int h, TCHAR* text)
{
	setbkmode(TRANSPARENT);
	setfillcolor(LIGHTGREEN);
	fillroundrect(x, y, x + w, y + h, 10, 10);
	// 输出字符串(MBCS 字符集)
	TCHAR s1[] = "楷体";
	settextstyle(30, 0, s1);
	TCHAR s[50] = "hello";

	int tx = x + (w - textwidth(text)) / 2;
	int ty = y + (h - textheight(text)) / 2;

	outtextxy(tx, ty, text);

}

void display()
{
	int	lengthcnt = 2;//纵向列数
	int lengthlim = 35;//纵向单位
	//int	widthcnt = 0;//横向行数
	int	widthlim = 6;//横向单位
	int width = 0;
	bool stopsignal = false;//停止打印最短路路径标志
	while (!stopsignal)
	{
		string templine = "";
		for (int i = outans.disans.size() - 1; i >= 0; i--)
		{
			if (width > 900)
			{
				lengthcnt++;
				width = 0;
			}
			if (i == outans.disans.size() - 1)
			{
				templine = findbelong(outans.disans[i], outans.disans[i - 1]);
				lengthcnt++;
				setbkmode(TRANSPARENT);
				setfillcolor(LIGHTRED);
				int	strlength = templine.size();
				fillroundrect(20, lengthlim * lengthcnt, 20 + strlength * 15, lengthlim * lengthcnt + 25, 10, 10);
				settextstyle(25, 0, "黑体");
				setbkmode(TRANSPARENT);
				settextcolor(WHITE);
				outtextxy(20, lengthlim * lengthcnt, templine.c_str());
				lengthcnt++;
				//widthcnt = 0;
			}	//输出打印几号线


			setbkmode(TRANSPARENT);
			setfillcolor(LIGHTBLUE);
			int	strlength = outans.disans[i].size();
			fillroundrect(width, lengthlim * lengthcnt, width + 13 * strlength, lengthlim * lengthcnt + 25, 10, 10);
			settextstyle(25, 0, "楷体");
			setbkmode(TRANSPARENT);
			settextcolor(YELLOW);
			outtextxy(width, lengthlim * lengthcnt, outans.disans[i].c_str());
			width += 13 * strlength + widthlim;
			//widthcnt++;

			if (i > 0 && findbelong(outans.disans[i], outans.disans[i - 1]) != templine)
			{
				templine = findbelong(outans.disans[i], outans.disans[i - 1]);
				lengthcnt++;
				setbkmode(TRANSPARENT);
				setfillcolor(LIGHTRED);
				int	strlength1 = templine.size();
				fillroundrect(20, lengthlim * lengthcnt, 20 + strlength1 * 15, lengthlim * lengthcnt + 25, 10, 10);
				settextstyle(25, 0, "黑体");
				setbkmode(TRANSPARENT);
				settextcolor(WHITE);
				outtextxy(20, lengthlim * lengthcnt, templine.c_str());
				lengthcnt++;
				//widthcnt = 0;
				width = 0;


				setbkmode(TRANSPARENT);
				setfillcolor(LIGHTBLUE);
				int	strlength = outans.disans[i].size();
				fillroundrect(width + 0, lengthlim * lengthcnt, width + 0 + 13 * strlength, lengthlim * lengthcnt + 25, 10, 10);
				settextstyle(25, 0, "楷体");
				setbkmode(TRANSPARENT);
				settextcolor(YELLOW);
				outtextxy(width + 0, lengthlim * lengthcnt, outans.disans[i].c_str());
				//widthcnt++;
				width += strlength * 13 + widthlim;
			}	//输出打印几号线

		}
		stopsignal = true;
	}
	setbkmode(TRANSPARENT);
	setfillcolor(WHITE);
	fillroundrect(700, 10, 700 + 300, 10 + 25, 10, 10);
	settextstyle(25, 0, "隶书");
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(700, 10, "总距离:");
	char grade[100] = "";
	sprintf(grade, "%d", outans.Odistance);
	outtextxy(800, 10, grade);

	setbkmode(TRANSPARENT);
	setfillcolor(WHITE);
	fillroundrect(700, 40, 700 + 300, 40 + 25, 10, 10);
	settextstyle(25, 0, "隶书");
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(700, 40, "预计时间:");
	char grade1[100] = "";
	sprintf(grade1, "%d", outans.distime);
	outtextxy(825, 40, grade1);

	setbkmode(TRANSPARENT);
	setfillcolor(WHITE);
	fillroundrect(700, 70, 700 + 300, 70 + 25, 10, 10);
	settextstyle(25, 0, "隶书");
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(700, 70, "预计花费:");
	char grade2[100] = "";
	sprintf(grade2, "%d", outans.Dcostmoney);
	outtextxy(825, 70, grade2);

	setbkmode(TRANSPARENT);
	setfillcolor(YELLOW);
	fillroundrect(200, 50, 200 + 210, 50 + 35, 10, 10);
	settextstyle(35, 0, "宋体");
	setbkmode(TRANSPARENT);
	settextcolor(CYAN);
	outtextxy(200, 50, "最短距离策略");


	/*setbkmode(TRANSPARENT);
	setfillcolor(LIGHTBLUE);
	fillroundrect(10, 100, 10 + 75, 100 + 25, 10, 10);
	settextstyle(25, 0, "楷体");
	setbkmode(TRANSPARENT);
	settextcolor(YELLOW);
	outtextxy(10, 100, "西直门");*/
}


void display2()

{
	int	lengthcnt = 2;//纵向列数
	int lengthlim = 35;//纵向单位
	//int	widthcnt = 0;//横向行数
	int	widthlim = 6;//横向单位
	int width = 0;
	bool stopsignal = false;//停止打印最短路路径标志
	while (!stopsignal)
	{
		string templine = "";
		for (int i = outans.timans.size() - 1; i >= 0; i--)
		{
			if (width > 900)
			{
				lengthcnt++;
				width = 0;
			}
			if (i == outans.timans.size() - 1)
			{
				templine = findbelong(outans.timans[i], outans.timans[i - 1]);
				lengthcnt++;
				setbkmode(TRANSPARENT);
				setfillcolor(LIGHTRED);
				int	strlength = templine.size();
				fillroundrect(20, lengthlim * lengthcnt, 20 + strlength * 15, lengthlim * lengthcnt + 25, 10, 10);
				settextstyle(25, 0, "黑体");
				setbkmode(TRANSPARENT);
				settextcolor(WHITE);
				outtextxy(20, lengthlim * lengthcnt, templine.c_str());
				lengthcnt++;
				//widthcnt = 0;
			}	//输出打印几号线


			setbkmode(TRANSPARENT);
			setfillcolor(LIGHTBLUE);
			int	strlength = outans.timans[i].size();
			fillroundrect(width, lengthlim * lengthcnt, width + 13 * strlength, lengthlim * lengthcnt + 25, 10, 10);
			settextstyle(25, 0, "楷体");
			setbkmode(TRANSPARENT);
			settextcolor(YELLOW);
			outtextxy(width, lengthlim * lengthcnt, outans.timans[i].c_str());
			width += 13 * strlength + widthlim;
			//widthcnt++;

			if (i > 0 && findbelong(outans.timans[i], outans.timans[i - 1]) != templine)
			{
				templine = findbelong(outans.timans[i], outans.timans[i - 1]);
				lengthcnt++;
				setbkmode(TRANSPARENT);
				setfillcolor(LIGHTRED);
				int	strlength1 = templine.size();
				fillroundrect(20, lengthlim * lengthcnt, 20 + strlength1 * 15, lengthlim * lengthcnt + 25, 10, 10);
				settextstyle(25, 0, "黑体");
				setbkmode(TRANSPARENT);
				settextcolor(WHITE);
				outtextxy(20, lengthlim * lengthcnt, templine.c_str());
				lengthcnt++;
				//widthcnt = 0;
				width = 0;


				setbkmode(TRANSPARENT);
				setfillcolor(LIGHTBLUE);
				int	strlength = outans.timans[i].size();
				fillroundrect(width + 0, lengthlim * lengthcnt, width + 0 + 13 * strlength, lengthlim * lengthcnt + 25, 10, 10);
				settextstyle(25, 0, "楷体");
				setbkmode(TRANSPARENT);
				settextcolor(YELLOW);
				outtextxy(width + 0, lengthlim * lengthcnt, outans.timans[i].c_str());
				//widthcnt++;
				width += strlength * 13 + widthlim;
			}	//输出打印几号线

		}
		stopsignal = true;
	}
	setbkmode(TRANSPARENT);
	setfillcolor(WHITE);
	fillroundrect(700, 10, 700 + 300, 10 + 25, 10, 10);
	settextstyle(25, 0, "隶书");
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(700, 10, "总距离:");
	char grade[100] = "";
	sprintf(grade, "%d", outans.timdist);
	outtextxy(800, 10, grade);

	setbkmode(TRANSPARENT);
	setfillcolor(WHITE);
	fillroundrect(700, 40, 700 + 300, 40 + 25, 10, 10);
	settextstyle(25, 0, "隶书");
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(700, 40, "预计时间:");
	char grade1[100] = "";
	sprintf(grade1, "%d", (int)outans.Otime);
	outtextxy(825, 40, grade1);

	setbkmode(TRANSPARENT);
	setfillcolor(WHITE);
	fillroundrect(700, 70, 700 + 300, 70 + 25, 10, 10);
	settextstyle(25, 0, "隶书");
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(700, 70, "预计花费:");
	char grade2[100] = "";
	sprintf(grade2, "%d", outans.Tcostmoney);
	outtextxy(825, 70, grade2);

	setbkmode(TRANSPARENT);
	setfillcolor(MAGENTA);
	fillroundrect(200, 50, 200 + 210, 50 + 35, 10, 10);
	settextstyle(35, 0, "宋体");
	setbkmode(TRANSPARENT);
	settextcolor(LIGHTCYAN);
	outtextxy(200, 50, "最短时间策略");


	/*setbkmode(TRANSPARENT);
	setfillcolor(LIGHTBLUE);
	fillroundrect(10, 100, 10 + 75, 100 + 25, 10, 10);
	settextstyle(25, 0, "楷体");
	setbkmode(TRANSPARENT);
	settextcolor(YELLOW);
	outtextxy(10, 100, "西直门");*/
}

void display3()
{
	int	lengthcnt = 2;//纵向列数
	int lengthlim = 35;//纵向单位
	//int	widthcnt = 0;//横向行数
	int	widthlim = 6;//横向单位
	int width = 0;
	bool stopsignal = false;//停止打印最短路路径标志
	while (!stopsignal)
	{
		string templine = "";
		for (int i = outans2.timans.size() - 1; i >= 0; i--)
		{
			if (width > 900)
			{
				lengthcnt++;
				width = 0;
			}
			if (i == outans2.timans.size() - 1)
			{
				templine = findbelong(outans2.timans[i], outans2.timans[i - 1]);
				lengthcnt++;
				setbkmode(TRANSPARENT);
				setfillcolor(LIGHTRED);
				int	strlength = templine.size();
				fillroundrect(20, lengthlim * lengthcnt, 20 + strlength * 15, lengthlim * lengthcnt + 25, 10, 10);
				settextstyle(25, 0, "黑体");
				setbkmode(TRANSPARENT);
				settextcolor(WHITE);
				outtextxy(20, lengthlim * lengthcnt, templine.c_str());
				lengthcnt++;
				//widthcnt = 0;
			}	//输出打印几号线


			setbkmode(TRANSPARENT);
			setfillcolor(LIGHTBLUE);
			int	strlength = outans2.timans[i].size();
			fillroundrect(width, lengthlim * lengthcnt, width + 13 * strlength, lengthlim * lengthcnt + 25, 10, 10);
			settextstyle(25, 0, "楷体");
			setbkmode(TRANSPARENT);
			settextcolor(YELLOW);
			outtextxy(width, lengthlim * lengthcnt, outans2.timans[i].c_str());
			width += 13 * strlength + widthlim;
			//widthcnt++;

			if (i > 0 && findbelong(outans2.timans[i], outans2.timans[i - 1]) != templine)
			{
				templine = findbelong(outans2.timans[i], outans2.timans[i - 1]);
				lengthcnt++;
				setbkmode(TRANSPARENT);
				setfillcolor(LIGHTRED);
				int	strlength1 = templine.size();
				fillroundrect(20, lengthlim * lengthcnt, 20 + strlength1 * 15, lengthlim * lengthcnt + 25, 10, 10);
				settextstyle(25, 0, "黑体");
				setbkmode(TRANSPARENT);
				settextcolor(WHITE);
				outtextxy(20, lengthlim * lengthcnt, templine.c_str());
				lengthcnt++;
				//widthcnt = 0;
				width = 0;


				setbkmode(TRANSPARENT);
				setfillcolor(LIGHTBLUE);
				int	strlength = outans2.timans[i].size();
				fillroundrect(width + 0, lengthlim * lengthcnt, width + 0 + 13 * strlength, lengthlim * lengthcnt + 25, 10, 10);
				settextstyle(25, 0, "楷体");
				setbkmode(TRANSPARENT);
				settextcolor(YELLOW);
				outtextxy(width + 0, lengthlim * lengthcnt, outans2.timans[i].c_str());
				//widthcnt++;
				width += strlength * 13 + widthlim;
			}	//输出打印几号线

		}
		stopsignal = true;
	}
	setbkmode(TRANSPARENT);
	setfillcolor(WHITE);
	fillroundrect(700, 10, 700 + 300, 10 + 25, 10, 10);
	settextstyle(25, 0, "隶书");
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(700, 10, "总距离:");
	/*char grade[100] = "";
	sprintf(grade, "%d", outans.timdist);
	outtextxy(800, 10, grade);*/

	setbkmode(TRANSPARENT);
	setfillcolor(WHITE);
	fillroundrect(700, 40, 700 + 300, 40 + 25, 10, 10);
	settextstyle(25, 0, "隶书");
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(700, 40, "预计时间:");
	/*char grade1[100] = "";
	sprintf(grade1, "%d", (int)outans.Otime);
	outtextxy(825, 40, grade1);*/

	setbkmode(TRANSPARENT);
	setfillcolor(WHITE);
	fillroundrect(700, 70, 700 + 300, 70 + 25, 10, 10);
	settextstyle(25, 0, "隶书");
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);
	outtextxy(700, 70, "预计花费:");
	/*char grade2[100] = "";
	sprintf(grade2, "%d", outans.Tcostmoney);
	outtextxy(825, 70, grade2);*/

	setbkmode(TRANSPARENT);
	setfillcolor(LIGHTGRAY);
	fillroundrect(200, 50, 200 + 210, 50 + 35, 10, 10);
	settextstyle(35, 0, "宋体");
	setbkmode(TRANSPARENT);
	settextcolor(LIGHTCYAN);
	outtextxy(200, 50, "最少换乘策略");


	/*setbkmode(TRANSPARENT);
	setfillcolor(LIGHTBLUE);
	fillroundrect(10, 100, 10 + 75, 100 + 25, 10, 10);
	settextstyle(25, 0, "楷体");
	setbkmode(TRANSPARENT);
	settextcolor(YELLOW);
	outtextxy(10, 100, "西直门");*/
}

bool showerror(string name)
{
	if (findStation(name) == -1)
	{
		HWND abc = GetHWnd();   //获取窗口句柄
		SetWindowText(abc, "Caicai:出现错误");   //修改窗口标题 
		MessageBox(abc, "您输入的名称不存在或被停用", "PiedpiperG", MB_OKCANCEL);  //设置对话框
		return	true;
	}
	return	false;
}

void forbiddenstation(string name)
{
	int cur = findStation(name);
	Stations* sta = station[cur].nextStaion;
	while (sta)
	{
		int nex = findRoad(station[cur].name, sta->name);
		road[nex].ifuse = false;
		sta = sta->nextStaion;
	}
	station[0].nextStaion = emptystation.nextStaion;
	station[cur].nextStaion = station[0].nextStaion;

}

void forbiddenroad(string name)
{
	for (int i = 1; i < Stationnum; i++)
	{
		for (int j = 0; j < 20; j++)
		{
			if (station[i].belongs[j] == name)
			{
				forbiddenstation(station[i].name);
				break;
			}
		}
	}
}

 run.cpp

#undef UNICODE
#undef _UNICODE
#include"function1.h"

int	main()
{
	readfile1();
	readfile2();
	initMap();
	//cout << findbelong("沙河", "昌平");
	//string start;
	//string end;
	/*print1();
	print2();*/
	HWND hwnd;
	hwnd = initgraph(1000, 750, SHOWCONSOLE);//创建一个窗口
	IMAGE background;//定义一个图片名.
	loadimage(&background, "./images/Bsubway.png", 1000, 750, 1);//从图片文件获取图像
	SetWindowText(hwnd, "PiedpiperG and Cai");
	int	Mode = 0;	//判断处于什么模式,默认值0为菜单模式
	char start[10] = {};
	char end[10] = {};
	char insertstart[10] = {};
	char insertend[10] = {};
	char insertlength[10] = {};
	char stopusesta[10] = {};
	char stopuselin[10] = {};
	while (1)
	{
		BeginBatchDraw(); //缓冲区打印,防止闪屏
		cleardevice();//刷新
		putimage(0, 0, &background);//绘制图像到屏幕,图片左上角坐标为(0,0)

		while (_kbhit())//如果有按键则进入,否则不进入循环
		{
			char userkey = 0;
			userkey = _getch();
			if (userkey == VK_ESCAPE)
			{
				Mode = 0;
			}
		}

		if (Mode == 0)
		{
			TCHAR s[50] = "1.查找线路";
			TCHAR s1[50] = "2.关停站点";
			TCHAR s2[50] = "3.关停线路";
			TCHAR s3[50] = "4.插入路线";
			button(391, 200, 170, 50, s);
			button(391, 300, 170, 50, s1);
			button(391, 400, 170, 50, s2);
			button(391, 500, 170, 50, s3);
			ExMessage msg;
			if (peekmessage(&msg, EM_MOUSE))
			{
				switch (msg.message)
				{
				case WM_LBUTTONDOWN:
					if (msg.x >= 391 && msg.x <= 391 + 170 && msg.y >= 200 && msg.y <= 200 + 50)
					{
						cout << "!" << endl;
						Mode = 1;
						//在此处写下按钮点击时要执行的函数,实现相应的功能
					}
					if (msg.x >= 391 && msg.x <= 391 + 170 && msg.y >= 300 && msg.y <= 300 + 50)
					{
						cout << "?" << endl;
						Mode = 2;
						//在此处写下按钮点击时要执行的函数,实现相应的功能  
					}
					if (msg.x >= 391 && msg.x <= 391 + 170 && msg.y >= 400 && msg.y <= 400 + 50)
					{
						cout << "@" << endl;
						Mode = 3;
						//在此处写下按钮点击时要执行的函数,实现相应的功能
					}
					if (msg.x >= 391 && msg.x <= 391 + 170 && msg.y >= 500 && msg.y <= 500 + 50)
					{
						cout << "&" << endl;
						Mode = 4;
						//在此处写下按钮点击时要执行的函数,实现相应的功能
					}
					break;
				default:
					break;
				}
			}

		}
		else if (Mode == 1)
		{


			TCHAR s[50] = "请输入起点";
			TCHAR s1[50] = "请输入终点";
			TCHAR s2[50] = "确认";
			button(391, 200, 250, 50, s);
			button(391, 300, 250, 50, s1);
			button(391, 400, 250, 50, s2);
			ExMessage msg;
			if (peekmessage(&msg, EM_MOUSE))
			{

				switch (msg.message)
				{
				case WM_LBUTTONDOWN:
					//cout << "!!!!!!!" << endl;
					if (msg.x >= 391 && msg.x <= 391 + 250 && msg.y >= 200 && msg.y <= 200 + 50)
					{
						cout << "输入起点" << endl;
						InputBox(start, 100, "请输入起点");
						if (showerror(start))
						{
							start[0] = '\0';
						}
						//在此处写下按钮点击时要执行的函数,实现相应的功能
					}
					if (msg.x >= 391 && msg.x <= 391 + 250 && msg.y >= 300 && msg.y <= 300 + 50)
					{
						cout << "输入终点" << endl;
						InputBox(end, 100, "请输入终点");
						if (showerror(end))
						{
							end[0] = '\0';
						}
						//在此处写下按钮点击时要执行的函数,实现相应的功能  
					}
					if (msg.x >= 391 && msg.x <= 391 + 250 && msg.y >= 400 && msg.y <= 400 + 50)
					{
						cout << "确认" << endl;
						string s = start;
						string e = end;
						dijkstra(s, e);
						dijkstra2(s, e);
						dijkstra3(s, e);
						Mode = 9;
						//在此处写下按钮点击时要执行的函数,实现相应的功能  

					}
					break;
				default:
					break;
				}
			}
			setbkmode(TRANSPARENT);
			settextcolor(LIGHTBLUE);
			outtextxy(751, 200, start);
			outtextxy(751, 300, end);
		}
		else if (Mode == 9)
		{
			//cout << "9" << endl;
			display();
			TCHAR s[50] = "下一页";
			button(700, 700, 100, 25, s);
			ExMessage msg;
			if (peekmessage(&msg, EM_MOUSE))
			{

				switch (msg.message)
				{
				case WM_LBUTTONDOWN:
					//cout << "!!!!!!!" << endl;
					if (msg.x >= 700 && msg.x <= 700 + 75 && msg.y >= 700 && msg.y <= 700 + 25)
					{
						cout << "下一页" << endl;
						Mode = 10;
						//在此处写下按钮点击时要执行的函数,实现相应的功能
					}
					break;
				default:
					break;
				}
			}
		}
		else if (Mode == 10)
		{
			display2();
			TCHAR s[50] = "上一页";
			button(600, 700, 100, 25, s);
			TCHAR s1[50] = "下一页";
			button(700, 700, 100, 25, s1);
			ExMessage msg;
			if (peekmessage(&msg, EM_MOUSE))
			{

				switch (msg.message)
				{
				case WM_LBUTTONDOWN:
					//cout << "!!!!!!!" << endl;
					if (msg.x >= 600 && msg.x <= 600 + 75 && msg.y >= 700 && msg.y <= 700 + 25)
					{
						cout << "上一页" << endl;
						Mode = 9;
						//在此处写下按钮点击时要执行的函数,实现相应的功能
					}
					if (msg.x >= 700 && msg.x <= 700 + 75 && msg.y >= 700 && msg.y <= 700 + 25)
					{
						cout << "下一页" << endl;
						Mode = 11;
						//在此处写下按钮点击时要执行的函数,实现相应的功能
					}
					break;
				default:
					break;
				}
			}
		}
		else if (Mode == 11)
		{
			display3();
			TCHAR s[50] = "上一页";
			button(600, 700, 100, 25, s);
			ExMessage msg;
			if (peekmessage(&msg, EM_MOUSE))
			{

				switch (msg.message)
				{
				case WM_LBUTTONDOWN:
					//cout << "!!!!!!!" << endl;
					if (msg.x >= 600 && msg.x <= 600 + 75 && msg.y >= 700 && msg.y <= 700 + 25)
					{
						cout << "上一页" << endl;
						Mode = 10;
						//在此处写下按钮点击时要执行的函数,实现相应的功能
					}
					break;
				default:
					break;
				}
			}
		}
		else if (Mode == 2)
		{
			TCHAR s[50] = "输入想要停用的站点";
			TCHAR s2[50] = "确认";
			button(391, 200, 280, 50, s);
			button(391, 400, 280, 50, s2);
			ExMessage msg;
			if (peekmessage(&msg, EM_MOUSE))
			{

				switch (msg.message)
				{
				case WM_LBUTTONDOWN:
					//cout << "!!!!!!!" << endl;
					if (msg.x >= 391 && msg.x <= 391 + 250 && msg.y >= 200 && msg.y <= 200 + 50)
					{

						cout << "输入想要停用的站点" << endl;
						InputBox(stopusesta, 100, "输入想要停用的站点");
						if (showerror(stopusesta))
							stopusesta[0] = '\0';
						//在此处写下按钮点击时要执行的函数,实现相应的功能
					}
					if (msg.x >= 391 && msg.x <= 391 + 250 && msg.y >= 400 && msg.y <= 400 + 50)
					{
						cout << "确认2" << endl;
						string s = stopusesta;
						forbiddenstation(s);
						HWND abc = GetHWnd();   //获取窗口句柄
						SetWindowText(abc, "Caicai:操作成功");   //修改窗口标题 
						MessageBox(abc, "站点已被关闭", "PiedpiperG", MB_OKCANCEL);  //设置对话框
						//在此处写下按钮点击时要执行的函数,实现相应的功能  
					}
					break;
				default:
					break;
				}
			}
			setbkmode(TRANSPARENT);
			settextcolor(LIGHTBLUE);
			outtextxy(751, 200, stopusesta);
		}
		else if (Mode == 3)
		{
			TCHAR s[50] = "输入想要停用的线路";
			TCHAR s2[50] = "确认";
			button(391, 200, 280, 50, s);
			button(391, 400, 280, 50, s2);
			ExMessage msg;
			if (peekmessage(&msg, EM_MOUSE))
			{
				switch (msg.message)
				{
				case WM_LBUTTONDOWN:
					//cout << "!!!!!!!" << endl;
					if (msg.x >= 391 && msg.x <= 391 + 250 && msg.y >= 200 && msg.y <= 200 + 50)
					{

						cout << "输入想要停用的线路" << endl;
						InputBox(stopuselin, 100, "线路前+#如#1号线");

						//在此处写下按钮点击时要执行的函数,实现相应的功能
					}
					if (msg.x >= 391 && msg.x <= 391 + 250 && msg.y >= 400 && msg.y <= 400 + 50)
					{
						cout << "确认2" << endl;
						string s = stopuselin;
						forbiddenroad(s);
						HWND abc = GetHWnd();   //获取窗口句柄
						SetWindowText(abc, "Caicai:操作成功");   //修改窗口标题 
						MessageBox(abc, "线路已被关闭", "PiedpiperG", MB_OKCANCEL);  //设置对话框
						//在此处写下按钮点击时要执行的函数,实现相应的功能  
					}
					break;
				default:
					break;
				}
			}
			setbkmode(TRANSPARENT);
			settextcolor(LIGHTBLUE);
			outtextxy(751, 200, stopuselin);
		}
		else if (Mode == 4)
		{
			TCHAR s[50] = "请输入起点";
			TCHAR s1[50] = "请输入终点";
			TCHAR s2[50] = "确认";
			TCHAR s3[50] = "请输入距离";
			button(391, 200, 250, 50, s);
			button(391, 300, 250, 50, s1);
			button(391, 500, 250, 50, s2);
			button(391, 400, 250, 50, s3);
			ExMessage msg;

			if (peekmessage(&msg, EM_MOUSE))
			{

				switch (msg.message)
				{
				case WM_LBUTTONDOWN:
					//cout << "!!!!!!!" << endl;
					if (msg.x >= 391 && msg.x <= 391 + 250 && msg.y >= 200 && msg.y <= 200 + 50)
					{
						cout << "输入起点" << endl;
						InputBox(insertstart, 100, "请输入起点");
						cout << insertstart << endl;
						if (showerror(insertstart))
						{
							start[0] = '\0';
						}
						//在此处写下按钮点击时要执行的函数,实现相应的功能
					}
					if (msg.x >= 391 && msg.x <= 391 + 250 && msg.y >= 300 && msg.y <= 300 + 50)
					{
						cout << "输入终点" << endl;
						InputBox(insertend, 100, "请输入终点");
						cout << insertend << endl;

						//在此处写下按钮点击时要执行的函数,实现相应的功能  
					}
					if (msg.x >= 391 && msg.x <= 391 + 250 && msg.y >= 500 && msg.y <= 500 + 50)
					{
						cout << "确认" << endl;
						string s = insertstart;
						string e = insertend;
						insertroad(insertstart, insertend, insertlength);
						HWND abc = GetHWnd();   //获取窗口句柄
						SetWindowText(abc, "Caicai:操作成功");   //修改窗口标题 
						MessageBox(abc, "成功插入线路", "PiedpiperG", MB_OKCANCEL);  //设置对话框
						//在此处写下按钮点击时要执行的函数,实现相应的功能  

					}
					if (msg.x >= 391 && msg.x <= 391 + 250 && msg.y >= 400 && msg.y <= 400 + 50)
					{
						cout << "输入距离" << endl;
						InputBox(insertlength, 100, "请输入距离");

						//在此处写下按钮点击时要执行的函数,实现相应的功能  
					}
					break;
				default:
					break;
				}
			}
			setbkmode(TRANSPARENT);
			settextcolor(LIGHTBLUE);
			outtextxy(751, 200, insertstart);
			outtextxy(751, 300, insertend);
			outtextxy(751, 400, insertlength);
		}


		EndBatchDraw();//缓冲区打印
	}
	closegraph();//关闭窗口





}

  • 23
    点赞
  • 96
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值