第25章 每对顶点间的最短路径
25.1 最短路径与矩阵乘法
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
typedef struct graph_type *graph;
struct edge {
int u;
int v;
int w;
};
struct vertex {
char str_vertex[256]; //顶点的字符串表示,显示用
};
void vertex_ini(struct vertex *v)
{
strcpy(v->str_vertex, "");
}
struct graph_type {
int **adj;
struct vertex *vertex_array;
int v_num;
int e_num;
};
//顶点是编号为0~v_num-1的数,str_vertex是顶点的字符串表示,显示用
graph graph_create(int v_num, char *str_vertex[])
{
graph g = malloc(sizeof(struct graph_type));
g->v_num = v_num;
g->e_num = 0;
g->adj = malloc(sizeof(int *) * v_num);
for (int i = 0; i < v_num; i++) {
g->adj[i] = malloc(sizeof(int) * v_num);
for (int j = 0; j < v_num; j++) {
g->adj[i][j] = 0;
}
}
g->vertex_array = malloc(sizeof(struct vertex) * v_num);
for (int i = 0; i < v_num; i++) {
strcpy(g->vertex_array[i].str_vertex, str_vertex[i]);
}
return g;
}
void graph_destroy(graph g)
{
for (int i = 0; i < g->v_num; i++) {
free(g->adj[i]);
}
free(g->adj);
free(g->vertex_array);
free(g);
}
void graph_insert_edge(graph g, struct edge edge)
{
g->adj[edge.u][edge.v] = edge.w;
++g->e_num;
}
void graph_display(graph g)
{
printf("%d vertices,%d edges\n", g->v_num, g->e_num);
for (int i = 0; i < g->v_num; i++) {
printf("%s: ", g->vertex_array[i].str_vertex);
for (int j = 0; j < g->v_num; j++) {
if (g->adj[i][j] != 0) {
printf("%s,%d ", g->vertex_array[j].str_vertex,
g->adj[i][j]);
}
}
printf("\n");
}
}
typedef struct matrix_type *matrix;
struct matrix_type {
int row;
int col;
int **data;
};
matrix matrix_create(int row, int col)
{
if (row == 0)
return NULL;
matrix m = malloc(sizeof(struct matrix_type));
m->row = row;
m->col = col;
m->data = malloc(sizeof(int *) * row);
for (int i = 0; i < row; i++) {
m->data[i] = malloc(sizeof(int) * col);
for (int j = 0; j < col; j++) {
m->data[i][j] = 0;
}
}
return m;
}
void matrix_destroy(matrix m)
{
for (int i = 0; i < m->row; i++)
free(m->data[i]);
free(m->data);
free(m);
}
void matrix_display(matrix m)
{
for (int i = 0; i < m->row; ++i) {
for (int j = 0; j < m->col; ++j) {
printf("%2d ", m->data[i][j]);
}
printf("\n");
}
}
void matrix_multiply(matrix A, matrix B, matrix C)
{
if (A->col != B->row) {
return;
}
for (int i = 0; i < A->row; ++i) {
for (int j = 0; j < B->col; ++j) {
C->data[i][j] = 0;
for (int k = 0; k < A->col; ++k) {
C->data[i][j] += A->data[i][k] * B->data[k][j];
}
}
}
}
void matrix_copy(matrix mdst, matrix msrc)
{
if (mdst->row != msrc->row || mdst->col != msrc->col) {
matrix_destroy(mdst);
mdst->row = msrc->row;
mdst->col = msrc->col;
mdst->data = malloc(sizeof(int *) * mdst->row);
for (int i = 0; i < mdst->row; i++) {
mdst->data[i] = malloc(sizeof(int) * mdst->col);
}
}
for (int i = 0; i < mdst->row; i++) {
for (int j = 0; j < mdst->col; j++) {
mdst->data[i][j] = msrc->data[i][j];
}
}
}
void extend_shortest_paths(matrix in,
matrix weight,
matrix out, matrix parent_in, matrix parent_out)
{
int n = in->col;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
out->data[i][j] = in->data[i][j];
parent_out->data[i][j] = parent_in->data[i][j];
for (int k = 0; k < n; k++) {
int dis = (in->data[i][k] == INT_MAX
|| weight->data[k][j] ==
INT_MAX) ? INT_MAX : in->data[i][k]
+ weight->data[k][j];
if (dis < out->data[i][j]) {
out->data[i][j] = dis;
parent_out->data[i][j] =
parent_in->data[k][j];
}
}
}
}
}
void slow_all_pairs_shortest_paths(graph g, matrix out, matrix parent_out)
{
int n = g->v_num;
matrix weight = matrix_create(n, n);
matrix parent_in = matrix_create(n, n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i == j) {
weight->data[i][j] = 0;
parent_in->data[i][j] = i;
} else {
weight->data[i][j] =
g->adj[i][j] != 0 ? g->adj[i][j] : INT_MAX;
parent_in->data[i][j] =
g->adj[i][j] != 0 ? i : -1;
}
}
}
matrix in = matrix_create(weight->row, weight->col);
matrix_copy(in, weight);
for (int m = 2; m <= n - 1; m++) {
extend_shortest_paths(in, weight, out, parent_in, parent_out);
matrix_copy(in, out);
matrix_copy(parent_in, parent_out);
}
matrix_destroy(weight);
matrix_destroy(parent_in);
matrix_destroy(in);
}
void faster_all_pairs_shortest_paths(graph g, matrix out, matrix parent_out)
{
int n = g->v_num;
matrix weight = matrix_create(n, n);
matrix parent_in = matrix_create(n, n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i == j) {
weight->data[i][j] = 0;
parent_in->data[i][j] = i;
} else {
weight->data[i][j] =
g->adj[i][j] != 0 ? g->adj[i][j] : INT_MAX;
parent_in->data[i][j] =
g->adj[i][j] != 0 ? i : -1;
}
}
}
matrix in = matrix_create(weight->row, weight->col);
matrix_copy(in, weight);
for (int m = 1; m < n - 1; m *= 2) {
extend_shortest_paths(in, in, out, parent_in, parent_out);
matrix_copy(in, out);
matrix_copy(parent_in, parent_out);
}
matrix_destroy(weight);
matrix_destroy(parent_in);
matrix_destroy(in);
}
void print_all_pairs_shortest_path(graph g, matrix parent, int i, int j)
{
if (i == j) {
printf("%s ", g->vertex_array[i].str_vertex);
} else {
if (parent->data[i][j] == -1) {
printf("no path from %s to %s exist\n",
g->vertex_array[i].str_vertex,
g->vertex_array[j].str_vertex);
} else {
print_all_pairs_shortest_path(g, parent, i,
parent->data[i][j]);
printf("%s ", g->vertex_array[j].str_vertex);
}
}
}
int main()
{
//数据根据书上的图25-1
char *str_vertex[5] = { "1", "2", "3", "4", "5" };
graph g = graph_create(5, str_vertex);
struct edge edges[] =
{ {0, 1, 3}, {0, 2, 8}, {0, 4, -4}, {1, 4, 7}, {1, 3, 1}, {2, 1, 4},
{3, 2, -5}, {3, 0, 2}, {4, 3, 6}
};
for (unsigned i = 0; i < sizeof(edges) / sizeof(edges[0]); i++) {
graph_insert_edge(g, edges[i]);
}
graph_display(g);
matrix out = matrix_create(g->v_num, g->v_num);
matrix parent = matrix_create(g->v_num, g->v_num);
slow_all_pairs_shortest_paths(g, out, parent);
printf("慢速算法的最短路径矩阵:\n");
matrix_display(out);
printf("慢速算法的前驱矩阵:\n");
matrix_display(parent);
int i = 4;
int j = 1;
printf("path from %s to %s\n", str_vertex[i], str_vertex[j]);
print_all_pairs_shortest_path(g, parent, i, j);
printf("\n");
faster_all_pairs_shortest_paths(g, out, parent);
printf("快速算法的最短路径矩阵:\n");
matrix_display(out);
printf("快速算法的前驱矩阵:\n");
matrix_display(parent);
printf("path from %s to %s\n", str_vertex[i], str_vertex[j]);
print_all_pairs_shortest_path(g, parent, i, j);
printf("\n");
matrix_destroy(out);
matrix_destroy(parent);
graph_destroy(g);
return 0;
}