Floyd算法
Floyd算法
Dijkstra算法是用于解决单源最短路径问题的,Floyd算法则是解决点对之间最短路径问题的。Floyd算法的设计策略是动态规划,而Dijkstra采取的是贪心策略。当然,贪心算法就是动态规划的特例。
算法思想
点对之间的最短路径只会有两种情况:
- 两点之间有边相连,weight(Vi,Vj)即是最小的。
- 通过另一点:中介点,两点相连,使weight(Vi,Vv)+weight(Vv,Vj)最小。
Min_Distance(Vi,Vj)=min{weight(Vi,Vj),weight(Vi,Vv)+weight(Vv,Vj)}。正是基于这种背后的逻辑,再加上动态规划的思想,构成了Floyd算法。故当Vv取完所有顶点后,Distance(Vi,Vj)即可达到最小。Floyd算法的起点就是图的邻接矩阵。
题外话:代码本身不重要,算法思想才是精髓。思想极难得到,而有了思想,稍加经验即可写出代码。向思想的开创者致敬!
思想很难,代码却比较简单,直接上代码
代码
类定义
- #include<iostream>
- #include<iomanip>
- #include<stack>
- using namespace std;
- #define MAXWEIGHT 100
- #undef INFINITY
- #define INFINITY 1000
- class Graph
- {
- private:
- //顶点数
- int numV;
- //边数
- int numE;
- //邻接矩阵
- int **matrix;
- public:
- Graph(int numV);
- //建图
- void createGraph(int numE);
- //析构方法
- ~Graph();
- //Floyd算法
- void Floyd();
- //打印邻接矩阵
- void printAdjacentMatrix();
- //检查输入
- bool check(int, int, int);
- };
#include<iostream>
#include<iomanip>
#include<stack>
using namespace std;
#define MAXWEIGHT 100
#undef INFINITY
#define INFINITY 1000
class Graph
{
private:
//顶点数
int numV;
//边数
int numE;
//邻接矩阵
int **matrix;
public:
Graph(int numV);
//建图
void createGraph(int numE);
//析构方法
~Graph();
//Floyd算法
void Floyd();
//打印邻接矩阵
void printAdjacentMatrix();
//检查输入
bool check(int, int, int);
};
类实现
- //构造函数,指定顶点数目
- Graph::Graph(int numV)
- {
- //对输入的顶点数进行检测
- while (numV <= 0)
- {
- cout << "顶点数有误!重新输入 ";
- cin >> numV;
- }
- this->numV = numV;
- //构建邻接矩阵,并初始化
- matrix = new int*[numV];
- int i, j;
- for (i = 0; i < numV; i++)
- matrix[i] = new int[numV];
- for (i = 0; i < numV; i++)
- for (j = 0; j < numV; j++)
- {
- if (i == j)
- matrix[i][i] = 0;
- else
- matrix[i][j] = INFINITY;
- }
- }
- void Graph::createGraph(int numE)
- {
- /*
- 对输入的边数做检测
- 一个numV个顶点的有向图,最多有numV*(numV - 1)条边
- */
- while (numE < 0 || numE > numV*(numV - 1))
- {
- cout << "边数有问题!重新输入 ";
- cin >> numE;
- }
- this->numE = numE;
- int tail, head, weight, i;
- i = 0;
- cout << "输入每条边的起点(弧尾)、终点(弧头)和权值" << endl;
- while (i < numE)
- {
- cin >> tail >> head >> weight;
- while (!check(tail, head, weight))
- {
- cout << "输入的边不正确!请重新输入 " << endl;
- cin >> tail >> head >> weight;
- }
- matrix[tail][head] = weight;
- i++;
- }
- }
- Graph::~Graph()
- {
- int i;
- for (i = 0; i < numV; i++)
- delete[] matrix[i];
- delete[]matrix;
- }
- /*
- 弗洛伊德算法
- 求各顶点对之间的最短距离
- 及其路径
- */
- void Graph::Floyd()
- {
- //为了不修改邻接矩阵,多用一个二维数组
- int **Distance = new int*[numV];
- int i, j;
- for (i = 0; i < numV; i++)
- Distance[i] = new int[numV];
- //初始化
- for (i = 0; i < numV; i++)
- for (j = 0; j < numV; j++)
- Distance[i][j] = matrix[i][j];
- //prev数组
- int **prev = new int*[numV];
- for (i = 0; i < numV; i++)
- prev[i] = new int[numV];
- //初始化prev
- for (i = 0; i < numV; i++)
- for (j = 0; j < numV; j++)
- {
- if (matrix[i][j] == INFINITY)
- prev[i][j] = -1;
- else
- prev[i][j] = i;
- }
- int d, v;
- for (v = 0; v < numV; v++)
- for (i = 0; i < numV; i++)
- for (j = 0; j < numV; j++)
- {
- d = Distance[i][v] + Distance[v][j];
- if (d < Distance[i][j])
- {
- Distance[i][j] = d;
- prev[i][j] = v;
- }
- }
- //打印Distance和prev数组
- cout << "Distance..." << endl;
- for (i = 0; i < numV; i++)
- {
- for (j = 0; j < numV; j++)
- cout << setw(3) << Distance[i][j];
- cout << endl;
- }
- cout << endl << "prev..." << endl;
- for (i = 0; i < numV; i++)
- {
- for (j = 0; j < numV; j++)
- cout << setw(3) << prev[i][j];
- cout << endl;
- }
- cout << endl;
- //打印顶点对最短路径
- stack<int> s;
- for (i = 0; i < numV; i++)
- {
- for (j = 0; j < numV; j++)
- {
- if (Distance[i][j] == 0);
- else if (Distance[i][j] == INFINITY)
- cout << "顶点 " << i << " 到顶点 " << j << " 无路径!" << endl;
- else
- {
- s.push(j);
- v = j;
- do{
- v = prev[i][v];
- s.push(v);
- } while (v != i);
- //打印路径
- cout << "顶点 " << i << " 到顶点 " << j << " 的最短路径长度是 "
- << Distance[i][j] << " ,其路径序列是...";
- while (!s.empty())
- {
- cout << setw(3) << s.top();
- s.pop();
- }
- cout << endl;
- }
- }
- cout << endl;
- }
- //释放空间
- for (i = 0; i < numV; i++)
- {
- delete[] Distance[i];
- delete[] prev[i];
- }
- delete[]Distance;
- delete[]prev;
- }
- //打印邻接矩阵
- void Graph::printAdjacentMatrix()
- {
- int i, j;
- cout.setf(ios::left);
- cout << setw(7) << " ";
- for (i = 0; i < numV; i++)
- cout << setw(7) << i;
- cout << endl;
- for (i = 0; i < numV; i++)
- {
- cout << setw(7) << i;
- for (j = 0; j < numV; j++)
- cout << setw(7) << matrix[i][j];
- cout << endl;
- }
- }
- bool Graph::check(int tail, int head, int weight)
- {
- if (tail < 0 || tail >= numV || head < 0 || head >= numV
- || weight <= 0 || weight >= MAXWEIGHT)
- return false;
- return true;
- }
//构造函数,指定顶点数目
Graph::Graph(int numV)
{
//对输入的顶点数进行检测
while (numV <= 0)
{
cout << "顶点数有误!重新输入 ";
cin >> numV;
}
this->numV = numV;
//构建邻接矩阵,并初始化
matrix = new int*[numV];
int i, j;
for (i = 0; i < numV; i++)
matrix[i] = new int[numV];
for (i = 0; i < numV; i++)
for (j = 0; j < numV; j++)
{
if (i == j)
matrix[i][i] = 0;
else
matrix[i][j] = INFINITY;
}
}
void Graph::createGraph(int numE)
{
/*
对输入的边数做检测
一个numV个顶点的有向图,最多有numV*(numV - 1)条边
*/
while (numE < 0 || numE > numV*(numV - 1))
{
cout << "边数有问题!重新输入 ";
cin >> numE;
}
this->numE = numE;
int tail, head, weight, i;
i = 0;
cout << "输入每条边的起点(弧尾)、终点(弧头)和权值" << endl;
while (i < numE)
{
cin >> tail >> head >> weight;
while (!check(tail, head, weight))
{
cout << "输入的边不正确!请重新输入 " << endl;
cin >> tail >> head >> weight;
}
matrix[tail][head] = weight;
i++;
}
}
Graph::~Graph()
{
int i;
for (i = 0; i < numV; i++)
delete[] matrix[i];
delete[]matrix;
}
/*
弗洛伊德算法
求各顶点对之间的最短距离
及其路径
*/
void Graph::Floyd()
{
//为了不修改邻接矩阵,多用一个二维数组
int **Distance = new int*[numV];
int i, j;
for (i = 0; i < numV; i++)
Distance[i] = new int[numV];
//初始化
for (i = 0; i < numV; i++)
for (j = 0; j < numV; j++)
Distance[i][j] = matrix[i][j];
//prev数组
int **prev = new int*[numV];
for (i = 0; i < numV; i++)
prev[i] = new int[numV];
//初始化prev
for (i = 0; i < numV; i++)
for (j = 0; j < numV; j++)
{
if (matrix[i][j] == INFINITY)
prev[i][j] = -1;
else
prev[i][j] = i;
}
int d, v;
for (v = 0; v < numV; v++)
for (i = 0; i < numV; i++)
for (j = 0; j < numV; j++)
{
d = Distance[i][v] + Distance[v][j];
if (d < Distance[i][j])
{
Distance[i][j] = d;
prev[i][j] = v;
}
}
//打印Distance和prev数组
cout << "Distance..." << endl;
for (i = 0; i < numV; i++)
{
for (j = 0; j < numV; j++)
cout << setw(3) << Distance[i][j];
cout << endl;
}
cout << endl << "prev..." << endl;
for (i = 0; i < numV; i++)
{
for (j = 0; j < numV; j++)
cout << setw(3) << prev[i][j];
cout << endl;
}
cout << endl;
//打印顶点对最短路径
stack<int> s;
for (i = 0; i < numV; i++)
{
for (j = 0; j < numV; j++)
{
if (Distance[i][j] == 0);
else if (Distance[i][j] == INFINITY)
cout << "顶点 " << i << " 到顶点 " << j << " 无路径!" << endl;
else
{
s.push(j);
v = j;
do{
v = prev[i][v];
s.push(v);
} while (v != i);
//打印路径
cout << "顶点 " << i << " 到顶点 " << j << " 的最短路径长度是 "
<< Distance[i][j] << " ,其路径序列是...";
while (!s.empty())
{
cout << setw(3) << s.top();
s.pop();
}
cout << endl;
}
}
cout << endl;
}
//释放空间
for (i = 0; i < numV; i++)
{
delete[] Distance[i];
delete[] prev[i];
}
delete[]Distance;
delete[]prev;
}
//打印邻接矩阵
void Graph::printAdjacentMatrix()
{
int i, j;
cout.setf(ios::left);
cout << setw(7) << " ";
for (i = 0; i < numV; i++)
cout << setw(7) << i;
cout << endl;
for (i = 0; i < numV; i++)
{
cout << setw(7) << i;
for (j = 0; j < numV; j++)
cout << setw(7) << matrix[i][j];
cout << endl;
}
}
bool Graph::check(int tail, int head, int weight)
{
if (tail < 0 || tail >= numV || head < 0 || head >= numV
|| weight <= 0 || weight >= MAXWEIGHT)
return false;
return true;
}
主函数
- int main()
- {
- cout << "******Floyd***by David***" << endl;
- int numV, numE;
- cout << "建图..." << endl;
- cout << "输入顶点数 ";
- cin >> numV;
- Graph graph(numV);
- cout << "输入边数 ";
- cin >> numE;
- graph.createGraph(numE);
- cout << endl << "Floyd..." << endl;
- graph.Floyd();
- system("pause");
- return 0;
- }
int main()
{
cout << "******Floyd***by David***" << endl;
int numV, numE;
cout << "建图..." << endl;
cout << "输入顶点数 ";
cin >> numV;
Graph graph(numV);
cout << "输入边数 ";
cin >> numE;
graph.createGraph(numE);
cout << endl << "Floyd..." << endl;
graph.Floyd();
system("pause");
return 0;
}
运行
小结
Floyd算法代码看似很长,其实并不难。代码中很多都是用于准备工作和输出,关键代码就是三层for循环。
若有所帮助,顶一个哦!
专栏目录: