Goal: Practice the algorithms of shortest pathproblem.
Task:用一个有向图表示给定的n个(要求至少10个)城市(或校园中的一些地点)及其之间的道路、距离情况,道路是有方向的。要求完成功能:根据用户输入的任意两个城市,给出这两个城市之间的最短距离及其路径。
要求使用真实地点及其位置,可以使用百度地图获得各点坐标,或者获取可达的两点间距离。
采用Dijkstra算法
Dijkstra算法是由荷兰计算机科学家艾兹格·迪科斯彻发现的。算法解决的是有向图中最短路径问题。
举例来说,如果图中的顶点表示城市,而边上的权重表示著城市间开车行经的距离。 Dijkstra算法可以用来找到两个城市之间的最短路径。
Dijkstra算法的输入包含了一个有权重的有向图G,以及G中的一个来源顶点S。 我们以V表示G中所有顶点的集合。图中的每一个边,都是两个顶点所形成的有序元素对。(u,v)表示从顶点u到v有路径相连。 假设E为所有边的集合,而边的权重则由权重函数w: E → [0, ∞]定义。 因此,w(u,v)就是从顶点u到顶点v的非负花费值(cost)。 边的花费可以想像成两个顶点之间的距离。任两点间路径的花费值,就是该路径上所有边的花费值总和。 已知有V中有顶点s及t,Dijkstra算法可以找到s到t的最低花费路径(i.e. 最短路径)。 这个算法也可以在一个图中,找到从一个顶点s到任何其他顶点的最短路径。
采用不同颜色标注配图路线防止混淆
想到了离散数学的哈密顿图
#include <iostream>
#include <windows.h>
#include <stdlib.h>
#include <conio.h>
using namespace std;
int arrow(int up,int down);
void title();
void gotoxy(int xpos, int ypos);
void frontPage();
int main();
void search_path();
void quit();
void find_the_path(const int start, const int dest, int& shortest, int * path);
int minVertex(int* D);
void print_path(int * path, int dest, int start);
class Graph
{
public:
virtual int verNum() = 0;
virtual int edgNum() = 0;
virtual int firstNghbr(int v) = 0;
virtual int nextNghbr(int v1, int v2) = 0;
virtual void setEdge(int v1, int v2, int wgt) = 0;
virtual void delEdge(int v1, int v2) = 0;
virtual int weight(int v1, int v2) = 0;
virtual int getMark(int v) = 0;
virtual void setMark(int v, int val) = 0;
};
class Graphm : public Graph
{
private:
int numVertex, numEdge;
int **matrix;
int *mark;
public:
Graphm()
{}
Graphm(int numVert) //声明一张图(用邻接矩阵方法实现)
{
int i,j;
numVertex = numVert;
numEdge = 0;
mark = new int[numVert];
for(i=0; i<numVertex; i++)
mark[i] = 0; //初始化各点访问情况为0,即未访问
matrix = (int**) new int*[numVertex];
for(i=0; i<numVert; i++)
matrix[i] = new int[numVertex];
for(i=0; i<numVertex; i++)
for(j=0; j<numVertex; j++)
matrix[i][j] = 0; //权为0表示两点间没有边连接
}
~Graphm()
{
delete [] mark;
int i;
for(i=0; i<numVertex; i++)
delete [] matrix[i];
delete [] matrix;
}
int verNum()
{
return numVertex;
}
int edgNum()
{
return numEdge;
}
int firstNghbr(int v)
{
int i;
for(i=0; i<numVertex; i++)
if(matrix[v][i] != 0)
return i;
return i; //若无第一个邻接结点返回节点数
}
int nextNghbr(int v1, int v2)
{
int i;
for(i=v2+1; i<numVertex; i++)
if(matrix[v1][i] != 0)
return i;
return i;
}
void setEdge(int v1, int v2, int wgt)
{
if(matrix[v1][v2] == 0)
numEdge++;
matrix[v1][v2] = wgt;
}
void delEdge(int v1, int v2)
{
if(matrix[v1][v2] != 0)
numEdge--;
matrix[v1][v2] = 0;
}
int weight(int v1, int v2)
{
return matrix[v1][v2];
}
int getMark(int v)
{
return mark[v];
}
void setMark(int v, int val)
{
mark[v] = val;
}
};
class City
{
private:
int id;
char * cityName;
public:
City()
{}
City(int newId, char* newName)
{
id = newId;
cityName = newName;
}
char* getCityName()
{
return cityName;
}
};
City* cityDB = new City[10]; //声明十个城市
Graphm cityGraph = Graphm(10); //声明城市间火车路线图
void gotoxy(int xpos, int ypos)
{
COORD scrn;
HANDLE hOuput = GetStdHandle(STD_OUTPUT_HANDLE);
scrn.X = xpos; scrn.Y = ypos;
SetConsoleCursorPosition(hOuput,scrn);
}
void title()
{
gotoxy(0,0);
cout<<"**********************************************************************"<<endl;
cout<<endl;
cout<<" 欢迎使用城市间最短里程路径查询程序 "<<endl;
cout<<endl;
cout<<"**********************************************************************"<<endl;
}
int arrow(int up,int down)
{
int i,j,c;
gotoxy(20,up);
j=up;
cout<<"-->";
for(i=0;i<10000;i++)
{
if(j>down)
{
gotoxy(20,j);
cout<<" ";
j=up;
gotoxy(20,j);
cout<<"-->";
}
if(j<up)
{
gotoxy(20,j);
cout<<" ";
j=down;
gotoxy(20,j);
cout<<"-->";
}
c=getch();
if(c==10 || c==13)
break;
if(c==224)
{
c=getch();
if(c == 80)
{
gotoxy(20,j+1);
cout<<"-->";
gotoxy(20,j);
cout<<" ";
j++;
}
if(c == 72)
{
gotoxy(20,j-1);
cout<<"-->";
gotoxy(20,j);
cout<<" ";
j--;
}
}
}
return j;
} //光标移动选择功能
void frontPage()
{
system("cls");
title();
cout<<endl;
cout<<endl;
cout<<endl;
cout<<endl;
cout<<" 请上下键选择操作:\n"<<endl;
cout<<endl;
cout<<endl;
cout<<" 查询城市间最短里程路径 "<<endl;
cout<<" 退出程序 "<<endl;
int j = arrow(13,14);
system("cls");
switch (j)
{
case 13:search_path();break;
case 14:quit();break;
}
}
void quit()
{
system("cls");
exit(0);
}
void search_path()
{
title();
cout<<endl;
int start=11, dest=11;
char start1,dest1;
cout<<"本程序存储有以下十个城市的线路信息,请输入其中任意两个城市ID获取之间最短路径: "<<endl;
cout<<endl;
cout<<" 0.北京 1.天津 2.上海 3.武汉 4.广州"<<endl;
cout<<" 5.南京 6.重庆 7.成都 8.西安 9.郑州"<<endl;
cout<<endl;
cout<<"提示:若输入的ID不在[0,9]范围内或两次输入同样的ID,输入界面会刷新等待重新输入";
while(start<0||start>=10||dest<0||dest>=10||start==dest)
{
gotoxy(17,13);
cout<<"输入出发城市ID: ";
gotoxy(17,14);
cout<<"输入目的城市ID: ";
gotoxy(33,13);
cin>>start1;
start=int(start1);
if(start1=='0')
start=10;
else if(start1=='1')
start=1;
else if(start1=='2')
start=2;
else if(start1=='3')
start=3;
else if(start1=='4')
start=4;
else if(start1=='5')
start=5;
else if(start1=='6')
start=6;
else if(start1=='7')
start=7;
else if(start1=='8')
start=8;
else if(start1=='9')
start=9;
gotoxy(33,14);
cin>>dest1;
dest=int(dest1);
if(dest1=='0')
dest=10;
else if(dest1=='1')
dest=1;
else if(dest1=='2')
dest=2;
else if(dest1=='3')
dest=3;
else if(dest1=='4')
dest=4;
else if(dest1=='5')
dest=5;
else if(dest1=='6')
dest=6;
else if(dest1=='7')
dest=7;
else if(dest1=='8')
dest=8;
else if(dest1=='9')
dest=9;
}
int shortest = 100000; //保存最短距离
int path[10]; //保存最短路径
int i;
for(i=0;i<10;i++)
path[i] = 11;
find_the_path(start,dest,shortest,path);
cout<<endl;
cout<<cityDB[start].getCityName()<<" 到 "<<cityDB[dest].getCityName()<<" 的最短里程为 "<<shortest<<" 公里, 路径为:"<<endl;
cout<<cityDB[start].getCityName()<<"-->";
print_path(path,dest,start);
cout<<cityDB[dest].getCityName()<<endl;
cout<<endl;
cout<<"按任意键返回主界面"<<endl;
system("pause");
for(i=0;i<10;i++)
cityGraph.setMark(i,0); //重置访问标记
frontPage();
}
void print_path(int * path, int dest, int start)
{
int k;
k = path[dest];
if(k == start)
return;
print_path(path,k,start);
cout<<cityDB[k].getCityName()<<"-->";
}
void find_the_path(const int start, const int dest, int& shortest, int * path) //Dijkstra算法应用
{
int D[10]; //存储设置的源城市到任意城市的估计最小长度
int i,v,w;
for(i=0; i<10; i++)
{
D[i] = 100000;
path[i] = -1;
}
D[start] = 0;
// path[start] = 0;
for(i=0; i<cityGraph.verNum(); i++)
{
v=minVertex(D);
if(D[v] == 100000)
return;
cityGraph.setMark(v,1);
for(w=cityGraph.firstNghbr(v); w<cityGraph.verNum(); w=cityGraph.nextNghbr(v,w))
{
if(D[w]>(D[v]+cityGraph.weight(v,w)))
{
D[w] = D[v] + cityGraph.weight(v,w);
path[w] = v;
}
}
}
shortest = D[dest];
}
int minVertex(int* D)
{
int i,v;
for(i=0; i<cityGraph.verNum(); i++)
{
if(cityGraph.getMark(i) == 0)
{
v = i;
break;
}
}
for(i++; i<cityGraph.verNum(); i++)
if((cityGraph.getMark(i) == 0) && (D[i] < D[v]))
v = i;
return v;
}
int main()
{
system("mode con cols=70 lines=23");
char c[20]="color 7f";
system(c); //对cmd窗口显示的调整变化(美化)
cityDB[0] = City(0,"北京");
cityDB[1] = City(1,"天津");
cityDB[2] = City(2,"上海");
cityDB[3] = City(3,"武汉");
cityDB[4] = City(4,"广州");
cityDB[5] = City(5,"南京");
cityDB[6] = City(6,"重庆");
cityDB[7] = City(7,"成都");
cityDB[8] = City(8,"西安");
cityDB[9] = City(9,"郑州");
cityGraph.setEdge(1,0,108);
cityGraph.setEdge(2,1,956);
cityGraph.setEdge(0,9,624);
cityGraph.setEdge(2,9,807);
cityGraph.setEdge(9,8,427);
cityGraph.setEdge(9,3,457);
cityGraph.setEdge(8,3,661);
cityGraph.setEdge(7,8,617);
cityGraph.setEdge(6,7,267);
cityGraph.setEdge(3,6,752);
cityGraph.setEdge(3,2,686);
cityGraph.setEdge(3,5,457);
cityGraph.setEdge(5,6,1199);
cityGraph.setEdge(2,4,1219);
cityGraph.setEdge(4,3,846);
cityGraph.setEdge(4,5,1142);
frontPage();
return 0;
}
能否用同一个调用形式,既能调用派生类又能调用基类的同名函数。在程序中不是通过不同的对象名去调用不同派生层次中的同名函数,而是通过指针调用它们。例如,用同一个语句“pt->display( );”可以调用不同派生层次中的display函数,只需在调用前给指针变量 pt 赋以不同的值(使之指向不同的类对象)即可。
C++中虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。
纯虚函数在基类中是没有定义的,必须在子类中加以实现,很像java中的接口函数!
百度解释:
-
中文名
- 虚函数 外文名
- virtual function 定 义
- 被virtual关键字修饰的成员函数