算法导论代码 第25章 每对顶点间的最短路径

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值