每对结点之间的最短路径(Floyd-Warshall 算法)
补充 ALL-PATHS 算法,增加前驱矩阵(Chp.25.2),使得在求出结点间的最短路径长度矩阵
A 后,能够推导出每对结点间的最短路径。
1)测试文件:
Input file:in.dat
格式:第一行为一个整数,表示测试用例的组数,其后跟相应组数的测试用例,每组测试用例包括:首行:一个整数,表示本组测试用例包含的结点数 n,其后跟 n 行其后:每行 n 个整数,表示结点间邻接关系及边的长度(邻接成本矩阵边的长度<100,100 即表示结点间没有边。
Output file:out.dat
格式:第一行为一个整数,表示测试用例的组数,其后跟相应组数的测试用例每组测试用例输出包括:首行:一个整数,表示本组测试用例包含的结点数 n,其后跟 n+n 2 行其后:开始的 n 行,每行 n 个整数,表示结点间最短路径的长度(A 矩阵)。路径的程度<32767,32767 即表示结点间没有可达的路径。其后 n 2 行,顺次输出结点对(1,1)、(1,2)、…、(1,n),(2,1)、(2,2)、…、(2,n)、…(n,1)、…、(n,n)之间的最短路径结点序列,结点间用空格隔开。(i,i)输出 i,若(i,j)之间没有路径,输出 NULL。
2)代码实现
#include<iostream>
#include<string>
#include<fstream>
#include<sstream>
#include<vector>
using namespace std;
#define Max_Num 10
#define INF 32767
typedef struct Graph {
// int var[Max_Num];
int edges[Max_Num][Max_Num];
int n; //顶点数
}Graph;
vector<Graph> graph;
vector<int> num;
vector<string> res;
int count_num; //测试用例的组数
void newGraph();
void Floyd(Graph G, ofstream &fileWrite);
void DisPath(int A[][Max_Num], int path[][Max_Num], int n, ofstream &fileWrite);
void PrintPath(int path[][Max_Num], int i, int j, ofstream &fileWrite);
template <class Type>
Type stringToNum(const string& str) {
istringstream iss(str);
Type num;
iss >> num;
iss.str("");
return num;
}
/*
*从文件中将数据读出来
*/
void file_read() {
string str2, str1 = "";
int i = 0;
ifstream fileRead("in.dat");
if (fileRead.is_open()) {
while (getline(fileRead, str2, '\n')) {
if (i >= 1) {
if (str2.find(" ") != -1) {
str1.append(str2 + " ");
}
else {
//num里面存放当前是多少维数组
num.push_back(stringToNum<int>(str2));
if (str1 != "") {
res.push_back(str1);
}
str1 = "";
}
} else if (i == 0) {
count_num = stringToNum<int>(str2);
}
i++;
}
res.push_back(str1);
fileRead.close();
}
}
/*
*将文件中的数据构建成图 然后放入vector中
*/
void newGraph() {
string temp;
Graph G;
for (int i = 0; i < res.size(); i++) {
vector<string> temp_str; //存放按照空格分开后的数字
int n = num[i];
stringstream input(res[i]);
while (input >> temp) {
temp_str.push_back(temp);
}
G.n = n;
//将每一次读到的完成二维数组添加到Graph之中
for (int j = 0; j < n; j++) {
for (int k = 0; k < n; k++) {
int tem = stringToNum<int>(temp_str[j*n + k]);
if (tem == 100) G.edges[j][k] = INF;
else G.edges[j][k] = tem;
}
}
graph.push_back(G);
}
}
void Floyd(Graph G, ofstream &fileWrite) {
int A[Max_Num][Max_Num], path[Max_Num][Max_Num];
//初始化图表 和路径表
for (int i = 0; i < G.n; i++) {
for (int j = 0; j < G.n; j++) {
A[i][j] = G.edges[i][j];
path[i][j] = -1;
}
}
//Floyd算法
for (int k = 0; k < G.n; k++) {
for (int i = 0; i < G.n; i++) {
for (int j = 0; j < G.n; j++) {
if (A[i][j] > (A[i][k] + A[k][j])) {
A[i][j] = A[i][k] + A[k][j];
path[i][j] = k;
}
}
}
}
DisPath(A, path, G.n, fileWrite);
}
void DisPath(int A[][Max_Num], int path[][Max_Num], int n, ofstream &fileWrite) {
//写入最短路径的距离
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (A[i][j] >= INF) {
if (i != j) {
fileWrite<<"NULL"<<" ";
}
} else {
fileWrite << A[i][j] <<" ";
}
}
fileWrite << endl;
}
//写入最短路径所经过的结点
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
fileWrite << "(" << i+1 << "," << j+1 << ")=>" <<"(";
if (A[i][j] >= INF) {
if (i != j) {
fileWrite << "NULL)" << endl;
}
else if(i == j)fileWrite << i << " ";
}
else {
fileWrite << i+1 << " ";
PrintPath(path, i, j, fileWrite);
fileWrite << j+1 << ")" <<endl;
}
}
}
}
/*
*递归打印路径信息
*/
void PrintPath(int path[][Max_Num], int i, int j, ofstream &fileWrite) {
int k = path[i][j];
if (k == -1) {
return;
}
PrintPath(path, i, k, fileWrite); //从i到k
fileWrite << k+1 << " ";
PrintPath(path, k, j, fileWrite); //从k到j
}
int main() {
file_read(); //将数据读入到文件中
newGraph(); //将读入的数据添加到vector<Graph>中
Graph G;
ofstream fileWrite("out.dat");//打开要写入的文件
fileWrite << count_num << endl;//写入测试的组数
for (int i = 0; i < graph.size(); i++) {
G = graph[i];
fileWrite << G.n << endl;
Floyd(G, fileWrite);
}
fileWrite.close();
return 0;
}