【C++】Floyd算法解决最短路径问题

最短路径问题

问题描述:平面上有n个点(n<=100),每个点的坐标均在-10000~10000之间。其中的一些点之间有连线。若有连线,则表示可从一个点到达另一个点,即两点间有通路,通路的距离为两点间的直线距离。现在的任务是找出从一点到另一点之间的最短距离。

输入:

第1行为整数n,表示图中顶点的个数。

第2行到第n+1行(共n行),每行两个整数x和y,描述了一个点的坐标(以一个空格分隔)。

第n+2行为一个整数m,表示图中连线的个数。

此后的m行,每行描述一条连线,由两个整数i和j组成,表示第i个点和第j个点之间有连线。

最后一行:两个整数s和t,分别表示源点和目标点。

输出:

仅1行,一个实数(保留两位小数),表示从s到t的最短路径长度。

输入样例:

5

0    0

2    0

2    2

0    2

3    1

5

1    2

1    3

1    4

2    5

3    5

1    5

输出样例:

3.41

代码示例
 

//author:Mitchell_Donovan
//date:5.18
#include
#include
#include//用于保留两位小数输出
using namespace std;

//边类
class Edge {
public:
	int from, to;
	double weight;
	Edge() {
		from = -1;
		to = -1;
		weight = 0;
	}
	Edge(int fromValue, int toValue, double weightValue) {
		from = fromValue;
		to = toValue;
		weight = weightValue;
	}
};

//图类
class Graph {
public:
	int numVertex;
	int numEdge;
	int* Mark;//标记图中顶点是否被访问过
	int* Indegree;//存放图中顶点的入度
	Graph(int num) {
		numVertex = num;
		numEdge = 0;
		Indegree = new int[numVertex];
		Mark = new int[numVertex];
		for (int i = 0; i < numVertex; i++) {
			Mark[i] = 0;//0表示未访问过
			Indegree[i] = 0;//入度设为0
		}
	}
	~Graph() {
		delete[]Mark;
		delete[]Indegree;
	}
	//判断是否为边
	bool isEdge(Edge oneEdge) {
		if (oneEdge.weight > 0 && oneEdge.weight < INFINITY && oneEdge.to >= 0) {
			return true;
		}
		else {
			return false;
		}
	}
	//访问
	void Visit(Graph& G, int v) {
		cout << v + 1 << " ";
		//cout << G.data[v];
	}
};

//用相邻矩阵表示图
class Graphm :public Graph {//类继承
private:
	double** matrix;//指向相邻矩阵的指针
public:
	Graphm(int num) :Graph(num) {
		matrix = (double**)new double* [numVertex];//申请二维数组空间
		for (int i = 0; i < numVertex; i++) {
			matrix[i] = new double[numVertex];
		}
		for (int i = 0; i < numVertex; i++) {//相邻矩阵初始化
			for (int j = 0; j < numVertex; j++) {
				matrix[i][j] = 0;
			}
		}
	}
	~Graphm() {
		for (int i = 0; i < numVertex; i++) {
			delete[]matrix[i];
		}
		delete[] matrix;
	}
	//返回顶点的第一条边
	Edge firstEdge(int oneVertex) {
		Edge myEdge;
		myEdge.from = oneVertex;
		for (int i = 0; i < numVertex; i++) {
			if (matrix[oneVertex][i] != 0) {
				myEdge.to = i;
				myEdge.weight = matrix[oneVertex][i];
				break;
			}
		}
		return myEdge;
	}
	//返回与已知边相同顶点的下一条边
	Edge nextEdge(Edge preEdge) {
		Edge myEdge;
		myEdge.from = preEdge.from;
		if (preEdge.to >= numVertex) {//不存在下一条边
			return myEdge;
		}
		for (int i = preEdge.to + 1; i < numVertex; i++) {
			if (matrix[preEdge.from][i] != 0) {
				myEdge.to = i;
				myEdge.weight = matrix[preEdge.from][i];
				break;
			}
		}
		return myEdge;
	}
	//为图设置一条边
	void setEdge(int from, int to, double weight) {
		if (matrix[from][to] <= 0) {//如果原边不存在
			numEdge++;
			Indegree[to]++;
		}
		matrix[from][to] = weight;
	}
	//删除图的一条边
	void delEdge(int from, int to) {
		if (matrix[from][to] > 0) {//如果原边存在
			numEdge--;
			Indegree[to]--;
		}
		matrix[from][to] = 0;
	}
};

//结构体Dist用于保存最短路径信息
struct Dist {
	int index;//顶点的索引项
	double length;//当前最短路径长度
	int pre;//路径最后经过的顶点
};

//递归函数print用于输出具体路径
void print(int from, int to, Dist*& D) {
	if (D[to].pre == from) {
		cout << from << "->" << to;
	}
	else {
		print(from, D[to].pre, D);
		cout << "->" << to;
	}
}

void print(int from, int to, Dist**& D) {
	if (D[from][to].pre == from) {
		cout << from << "->" << to;
	}
	else {
		print(from, D[from][to].pre, D);
		cout << "->" << to;
	}
}

void Floyd(Graphm& G,int from,int to) {
	Dist** D = new Dist * [G.numVertex];
	for (int i = 0; i < G.numVertex; i++) {
		D[i] = new Dist[G.numVertex];
	}
	for (int i = 0; i < G.numVertex; i++) {//初始化D数组
		for (int j = 0; j < G.numVertex; j++) {
			if (i == j) {
				D[i][j].length = 0;
				D[i][j].pre = i;
			}
			else {
				D[i][j].length = INFINITY;
				D[i][j].pre = -1;
			}
		}
	}
	for (int i = 0; i < G.numVertex; i++) {
		for (Edge e = G.firstEdge(i); G.isEdge(e); e = G.nextEdge(e)) {
			D[i][e.to].length = e.weight;
			D[i][e.to].pre = i;
		}
	}
	//顶点i到顶点j的路径经过顶点v如果变短,则更新路径长度
	for (int v = 0; v < G.numVertex; v++) {
		for (int i = 0; i < G.numVertex; i++) {
			for (int j = 0; j < G.numVertex; j++) {
				if (D[i][j].length > (D[i][v].length + D[v][j].length)) {
					D[i][j].length = D[i][v].length + D[v][j].length;
					D[i][j].pre = D[v][j].pre;
				}
			}
		}
	}
	//打印出结果
	cout << "最短路径长度为:" << fixed << setprecision(2) << D[from][to].length << endl;//保留两位小数输出
	cout << "具体路径为:";
	print(from, to, D);
}



int main() {
	int n, m;
	cout << "顶点个数:";
	cin >> n;
	Graphm test(n);
	struct position {
		int x;
		int y;
	};
	position* pos = new position[n];
	for (int i = 0; i < n; i++) {
		cout << "第" << i + 1 << "个点的坐标:";
		cin >> pos[i].x;
		cin >> pos[i].y;
	}
	cout << "图中连线的个数:";
	cin >> m;
	int from, to;
	for (int i = 0; i < m; i++) {
		cout << "第" << i + 1 << "条边的起点和终点:";
		cin >> from;
		cin >> to;
		double length = sqrt(pow(pos[to - 1].x - pos[from - 1].x, 2) + pow(pos[to - 1].y - pos[from - 1].y, 2));
		test.setEdge(from - 1, to - 1, length);
		test.setEdge(to - 1, from - 1, length);
	}
	cout << "请输入源点和目标点:";
	cin >> from;
	cin >> to;
	Floyd(test, from - 1, to - 1);
}

输出示例

【C++】Floyd算法解决最短路径问题_第1张图片

补充参考

C++优先队列自定义排序总结

你可能感兴趣的:(数据结构,算法,c++,图,最短距离,Floyd)