VS2019
// MapRoutes.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include <iostream>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include <vector>
#include<Windows.h>
#define INFINITY 99999
using namespace std;
#define N 99999;
typedef struct {//cities的结构体
bool pass = false;
string country, city;
float latitude = 0, longitude = 0;
bool Visited = false;//用于深度遍历的辅助数组
bool ver[199];//辅助
}City, Vertex;
typedef struct
{//routes的结构体
string origin_city, destination_city;
string transport;
float time, cost;
string other_info;
}Route;
typedef struct {
Vertex* vertex;
Route arc[199][199];//这个要是写成动态分配的就更好了,我这里写“死”了
int vexnum, arcnum;
}Graph;
//顶点查找位置
int Locate(string city, City ct[])
{
int i = 0;
for (i = 0; i < 199; i++)
{
if (city == ct[i].city)
return i;//如果相同,就返回位置
}
return -1;
}
void getCity(City* ct);//读取城市文件
void getRoutes(Route* route);//读取路线文件
void Create(Graph& g, City* ct, Route* route);//创建邻接矩阵
void DFS(int ori, City* ct);//深度遍历
void DFStraverse(City* ct);
void get_shortest_DJS_path(Graph& g, City* ct, int depart, int dest, float D[], int S[], int predecessor[]);//获得最短路费路径
void get_shortest_time_DJS_path(Graph& g, City* ct,int depart,int dest,float D[],int S[]);//获得最短时间路径
void Visualize(Graph& g, int depart, int dest, vector<int>a);//可视化函数
//主函数
int main()
{
City ct[201];
Route route[1975];
//读取两个文件
getCity(ct);
getRoutes(route);
//创建邻接矩阵
Graph g;
Create(g, ct, route);
//深度优先遍历
cout << "深度遍历结果:" << endl;
DFStraverse(ct);//从ct[0]开始深度遍历
cout << endl;
//最短路径选择
int choice, depart, dest;//depart and dest 是出发点和目的地的代号
cout << "最短路径:" << endl;
cout << "1 for cost and 2 for time:";
cin >> choice;
string city1, city2;//起始点和目的地的城市名称
float D[199] = { 0 }; //用D[i]表示当前所找到的从始点depart到每个目的地城市的最短路径的路费或者时间
int S[199] = { 0 }; //已到达的最短路径的目的地的集合
int predecessor[199]; //存放顶点的前驱,方便输出最短路
//用户输入名称,由Locate函数确定每个城市位置
cout << "请输入起始城市名称:";
cin >> city1;
depart = Locate(city1, ct);
cout << "请输入目的地城市名称:";
cin >> city2;
dest = Locate(city2, ct);
//判断是否在范围内,不在则结束程序
if (depart > 199 || dest > 199 || depart < 0 || dest < 0)
{
cout << "找不到城市"<<endl;
exit(0);
}
int t1 = clock();//计时开始,做出选择
switch (choice)
{
case 1:
get_shortest_DJS_path(g, ct,depart,dest,D,S,predecessor); break;//如果选择为1 ,则查找最短路费路径,并进行可视化(最短路径里面调用可视化函数)
case 2:
get_shortest_time_DJS_path(g, ct, depart, dest, D, S); break;//如果选择为2 ,则查找最短时间路径,并进行可视化
default:
break;
}
int t2 = clock();
cout << "算法运行时间为:" << t2 - t1 << "ms" << endl;
}
//读取城市文件
void getCity(City* ct)
{
//读取函数
FILE* fp;
fp = fopen(".\\cities.csv", "r");//读取文件
if (!fp)
{//报错
cout << "ERROR!" << endl;
exit(0);
}
char ch;
int i = 0;
float f;
while (!feof(fp))
{
ch = fgetc(fp);
for (; ch != ','; ch = fgetc(fp))
{//读取逗号前面的字符,作为country
ct[i].country += ch;
}
ch = fgetc(fp);
for (; ch != ','; ch = fgetc(fp))
{//同country
ct[i].city += ch;
}
//输入经纬度
fscanf_s(fp, "%f,", &f);
ct[i].latitude = f;
fscanf_s(fp, "%f\n", &f);
ct[i].longitude = f;
i++;
}
fclose(fp);//关闭文件
}
//读取路线
void getRoutes(Route* route)
{
char ch;
int i;
FILE* fp1 = fopen(".\\routes.csv", "r");
if (!fp1)
{
cout << "error";
exit(0);
}
ch = fgetc(fp1);
i = 0;
while (!feof(fp1) && i < 1975)
{//读取文件,同城市读取
while (ch != ',') {
route[i].origin_city += ch; ch = fgetc(fp1);
}
ch = fgetc(fp1);
while (ch != ',')
{
route[i].destination_city += ch;
ch = fgetc(fp1);
}
ch = fgetc(fp1);
while (ch != ',')
{
route[i].transport += ch;
ch = fgetc(fp1);
}
fscanf_s(fp1, "%f,", &route[i].time);
fscanf_s(fp1, "%f,", &route[i].cost);
ch = fgetc(fp1);
while (ch != '\n')
{
route[i].other_info += ch; ch = fgetc(fp1);
}
ch = fgetc(fp1);
i++;
}
fclose(fp1);
}
//邻接矩阵
void Create(Graph& g, City* ct,Route *route)
{
//创建邻接矩阵
int j = 0, i = 0;
g.arcnum = 199 * 199;//边数
g.vexnum = 199;//顶点数
g.vertex = ct;
for (i = 0; i < 199; i++)
for (j = 0; j < 199; j++)
{
ct[i].ver[j] = false;//把第i个顶点到其他顶点状态初始化为0,未连通
if (i == j)
{//自己到自己时间和路径初始化为0
g.arc[i][j].cost = 0;
g.arc[i][j].time = 0;
}
else
{//其他初始化为最大
g.arc[i][j].cost = N;
g.arc[i][j].time =N;
}
}
for (i = 0; i < 1975; i++)
{//对边赋权值
int ori, de;
ori = Locate(route[i].origin_city, ct);//定位
de = Locate(route[i].destination_city, ct);
if (route[i].cost < g.arc[ori][de].cost)
{//判断,赋值
g.arc[ori][de].cost = route[i].cost;//把路费赋值给边
g.arc[ori][de].time = route[i].time;//把时间赋值给边
}
ct[ori].ver[de] =true;//把从第ori到第de顶点状态赋值为1,通路
}
}
//从ori点开始深度遍历
void DFS(int ori, City ct[])
{
cout <<"("<<ori<<","<< ct[ori].city<<")" << "--> ";//输出遍历的城市
ct[ori].Visited = true;//由于已经初始化为false,所以,遍历过的就变为true
for (int j = 0; j < 199; j++)
{
if (ct[ori].ver[j] == true && ct[j].Visited == false)//括号内容说明;ori与jz之间连通且第j 个顶点未被遍历到
{
DFS(j, ct);//递归遍历
}
}
}
void DFStraverse(City* ct)
{
int i;
for (i = 0; i < 199; i++)
{//从头到尾
ct[i].Visited = false;//全部为false:未遍历状态
}
for (i = 0; i < 199; i++)
{
if (!ct[i].Visited)//若第i未被遍历的话
DFS(i, ct);//调用DFS对第i 个顶点进行遍历输出
}
}
//判断当前顶点是否在数组S中,(S数组就是已经被选择过的顶点的集合)
bool has_selected(int S[], int i, int k) {
for (int j = 0; j < k; j++)
if (i == S[j])
return true;
return false;
}
//从数组D中选取最小值(主函数中说明:数组D是一个辅助向量,D[i]表示当前所找到的从始点deaprt到每个终点dest的最短路径的时间或费用。)
int search_min(float D[], int S[], int k) { //k为数组S中元素的个数,也就是说现在已经选了k条最短路径
int min = -1; //若为非连通图,则返回-1
int m = INFINITY;
for (int i = 0; i < 199; i++)
if (!has_selected(S, i, k) && (D[i] < m)) {
min = i;
m = D[i];
}
return min;
}
void get_shortest_DJS_path(Graph& g, City* ct, int depart, int dest, float D[], int S[], int predecessor[])
{
int min = 0, t = 0; //初始化当前寻找到的最短路径的终点
for (int i = 0; i < 199; i++) //初始化所有顶点的前驱都为起始城市
predecessor[i] = depart;
for (int j = 0; j < 199; j++)
D[j] = g.arc[depart][j].cost;//把费用赋值给D
for (int i = 0; i < 199; i++) {
for (int j = 0; j < 199; j++) {
if (j == depart) //防止寻找到的路径的起始点和终点相同
continue;
if (D[min] + g.arc[min][j].cost < D[j]) {
D[j] = D[min] + g.arc[min][j].cost;//更新最短路径的费用
predecessor[j] = min; // 前驱的建立
}
}
min = search_min(D, S, i); // 寻找当前最短路径,返回最短路径的终点
if (min == -1) {
cout << "两个城市之间无交通方式\n";
exit(0);
}
S[i] = min; //编号为min的顶点作为最短路径的终点,所以把此顶点放入S中
if (min == dest) //如果现在选择的最短路径的终点恰好是dest,则停止寻找最短路径,减少时间复杂度
break;
}
//输出最短路径的信息
vector<int>order;//存储倒序城市的数组
vector<int>vec_city;//正序输出数组
int pre = dest;
cout << "From " << g.vertex[dest].city << " to " << g.vertex[depart].city << endl;
cout << "路费为$" << D[dest] << endl;
cout << "最短路径为:";
order.push_back(Locate(g.vertex[dest].city, ct));//把目的地城市压入数组
for (int i = 0; pre != depart; i++) {//把城市倒序输入
pre = predecessor[pre];//找到前驱的代号,直到前驱为depart
order.push_back(Locate(g.vertex[pre].city, ct));//每个城市放入此数组,且是倒序的
}
for (int i =order.size()-1; i >0; i--)
{//正序输出
cout << g.vertex[order[i]].city << "- >";
vec_city.push_back(order[i]);
}
vec_city.push_back(order[0]);//放入起点城市
cout << g.vertex[order[0]].city <<endl;
int t0 = clock();
Visualize(g, depart, dest, vec_city);//调用可视化函数
int tt = clock();
cout << "算法运行时间为:" << tt - t0<< "ms" << endl;
}
//类似于路费的函数,把cost变成了time输出即可
void get_shortest_time_DJS_path(Graph& g, City* ct,int depart,int dest,float D[],int S[])
{
int min = 0; //当前寻找到的最短路径的终点
int predecessor[199]; //存放顶点的前驱,方便输出最短路
vector<int>order;
vector<int>vec_city;
for (int i = 0; i < 199; i++) //初始化所有顶点的前驱都为起始城市
predecessor[i] = depart;
for (int j = 0; j < 199; j++)
D[j] = g.arc[depart][j].time;
for (int i = 0; i < 199; i++) {
for (int j = 0; j < 199; j++) {
if (j == depart) //防止寻找到的路径的起始点和终点相同
continue;
if (D[min] + g.arc[min][j].time < D[j]) {
D[j] = D[min] + g.arc[min][j].time;
predecessor[j] = min; // 前驱的建立
}
}
min = search_min(D, S, i); // 寻找当前最短路径,返回最短路径的终点
if (min == -1) {
cout << "两个城市之间无交通方式\n";
exit(0);
}
S[i] = min; //编号为min的顶点作为最短路径的终点,所以把此顶点放入S中
if (min == dest) //如果现在选择的最短路径的终点恰好是dest,则停止寻找最短路径,减少时间复杂度
break;
}
//输出最短路径的信息
int pre = dest;
cout << "From " << g.vertex[dest].city << " to " << g.vertex[depart].city << endl;
cout << "时间为:" << D[dest] << "h"<<endl;
cout << "最短路径为:";
order.push_back(Locate(g.vertex[dest].city, ct));
for (int i = 0; pre != depart; i++) {//dest!=depart
pre = predecessor[pre];
order.push_back(Locate(g.vertex[pre].city, ct));
}
for (int i = order.size() - 1; i > 0; i--)
{
cout << g.vertex[order[i]].city << "- >";
vec_city.push_back(order[i]);
}
vec_city.push_back(order[0]);
cout << g.vertex[order[0]].city << endl;
Visualize(g, depart, dest, vec_city);
}
//可视化函数(复制API代码,进行修改)
void Visualize(Graph& g, int depart, int dest,vector<int>vec_city)
{
FILE* fp3;//打开文件
fp3 = fopen(".\\MyGraph.html", "w");
if (fp3 == NULL)
{//报错
cout << "error3";
exit(0);
}
int j = 0;
//s为API的代码
string s = "<!DOCTYPE html>\n\
<html>\t\
<head>\n\
<meta http-equiv = 'Content-Type' content = 'text/html; charset=utf-8' />\n\
<meta name = 'viewport' content = 'initial-scale=1.0, user-scalable=no' />\n\
<style type = 'text/css'>\
body, html, #allmap{ width: 100%; height: 100%; overflow: hidden; margin : 0; font-family:'wei ruan ya hei'; }\n\
#l-map{ height:100%; width:78%; float:left; border-right:2px solid #bcbcbc; }\n\
#r-result{ height:100%; width:20%; float:left; }\
</style>\n\
<script type = 'text/javascript' src = 'http://api.map.baidu.com/api?v=2.0&ak=nSxiPohfziUaCuONe4ViUP2N'></script>\n";
//修改了Title:"从起始到目的地的最短距离"
fprintf(fp3, "%s<title>Shortest path from %s to %s</title>\
</head><body><div id='allmap'></div></body>\
</html>\n\
<script type = 'text/javascript'>\n\
var map = new BMap.Map('allmap');\n\
var point = new BMap.Point(0,0);\n\
map.centerAndZoom(point, 2);\n\
map.enableScrollWheelZoom(true);\n", s.c_str(), g.vertex[depart].city.c_str(), g.vertex[dest].city.c_str());
for (j = 0; j < vec_city.size(); j++)//调用上面的存储正序城市的数组
{
int m;
m = vec_city[j];//m赋值为从depart到dest途经的城市的代码(顺序)
//加入经过的城市的顶点的经纬度,所属国家及城市名称
fprintf(fp3, "var marker%d =new BMap.Marker (new BMap.Point(%.4f,%.4f));\n\
map.addOverlay(marker%d);\n\
var infoWindow%d = new BMap.InfoWindow(\"<p style = 'font-size:14px;'>country%s<br/>city%s</p>\");\n\
marker%d.addEventListener(\"click\", function(){this.openInfoWindow(infoWindow%d);});\n\n", j, g.vertex[m].longitude, g.vertex[m].latitude, j, j, g.vertex[m].country.c_str(), g.vertex[m].city.c_str(), j, j);
if (j < vec_city.size() - 1)
{//判断,在到达最后一座城市之前,都有path,最后一座城市不执行这步
int n;
int t = j+1 ;//如果为J则不划线
n = vec_city[t];
fprintf(fp3, "var marker%d =new BMap.Marker (new BMap.Point(%.4f,%.4f));\n\
map.addOverlay(marker%d);\n\
var infoWindow%d = new BMap.InfoWindow(\"<p style = 'font-size:14px;'>country%s<br/>city%s</p>\");\n\
marker%d.addEventListener(\"click\", function(){this.openInfoWindow(infoWindow%d);});\n\n", t, g.vertex[n].longitude, g.vertex[n].latitude, t, t, g.vertex[n].country.c_str(), g.vertex[n].city.c_str(), t, t);
//画路径,里面“red”可以更换颜色
fprintf(fp3, "var path%d=new BMap.Polyline([\n\
new BMap.Point(%.4f,%.4f),\n\
new BMap.Point(%.4f,%.4f)],\n\
{ strokeColor:'red', strokeWeight : 2, strokeOpacity : 1.5 });\n\
map.addOverlay(path%d);\n\n", j, g.vertex[m].longitude, g.vertex[m].latitude, g.vertex[n].longitude, g.vertex[n].latitude, j);
}
}
fprintf(fp3, "</script>");
fclose(fp3);
ShellExecuteA(NULL, "open", ".\\MyGraph.html", NULL, NULL, 5);//弹出网页
}
结果:
问题解决:堆栈溢出:
1.项目–>属性–>链接器—>系统----->保留堆栈大小:更改数字从而增大堆栈大小---->确定,这样就可以运行了!(当然,也可以用其他更好的办法)。