数据结构_Floyd算法_python/c实例

overview:

在这里插入图片描述

the dynamic programming idea:

在这里插入图片描述
there,according to what your number count from(0/1)
if you from 1 to count ,the k<=n
else k<=n-1;

pseudocode:

在这里插入图片描述

exmaple input:

在这里插入图片描述

python code:

#让算法运行上述图的矩阵表示输入(本程序使用logging包调试,并且使用python3.8的f-string 字符串格式输出
import numpy as np
import math
import logging as l
# l.basicConfig(level=l.DEBUG)
inf = math.inf


def floyd(d):
    ''' the d is a graph table(n*n) '''
    n = len(d)
    precursor_table = [[None for i in range(n)] for j in range(n)]
    for i in range(n):
        for j in range(n):
            if i == j:
                continue
            if d[i][j] != inf:
                precursor_table[i][j] = i
    # print_matrix(precursor_table)
    # print("pre 0\n", np.array(precursor_table))

    l.debug(f'd:{d}')

    '''d[i][j] means that weight of a shortest path from i to j with 
    intermediate vertices belonging to the set {1, 2, …, k}. 
    Okay to omit superscripts, since extra relaxations can’t hurt.'''
    #
    # the k is the intermediate vertices' max numbers(upper bound)(number system)(not the size of the intermediate nodes points ).
    for k in range(n):
        ''' traverse the weight matrix in each level subproblem(indicated by k) '''
        # the i is the start node of the path(i,j)
        for i in range(n):
            # the j is the end node of the path(i,j)
            for j in range(n):
                l.debug(f'i,j={i,j}')
                # the classic relax operation:
                if d[i][j] > d[i][k]+d[k][j]:
                    d[i][j] = d[i][k]+d[k][j]
                    precursor_table[i][j] = precursor_table[k][j]

        # print("pre", k+1, "\n", np.array(precursor_table))
    return precursor_table
d = [
    [0, 3, 8, inf, -4],
    [inf, 0, inf, 1, 7],
    [inf, 4, 0, inf, inf],
    [2, inf, -5, 0, inf],
    [inf, inf, inf, 6, 0]

]
 
def print_matrix(d):
    for line in d:
        print(line) 
        
''' 调用floyd算法计算矩阵d(并将保存结果保存在d) (但函数返回值我设置为前驱矩阵)'''
precursor_table=floyd(d)
print_matrix(d)
                  
def print_precurcer(precursor_table,i,j):
    ''' from 0 count the index of the matrix and from 0 number the node in the graph '''
    precursor=precursor_table[i][j]
    # print(np.array(precursor_table).shape)
    # print((i,j))
    l.debug(f'i,j={i,j}')
    # print(f'i,j={i,j}')
    if i==j:
        # print()
        print(i,end=" ")#let it break line
    elif precursor==None:
        print("no path from",i,"to",j,"exists")
    else:
        print_precurcer(precursor_table,i,precursor)
        print(j,end=" ")
                
            

''' 如果是矩阵从1开始计数,那么调用如下函数(直接赋值给print_precurcer函数的引用) '''
def print_precurcer_count_from_1(precursor_table,i,j):
    precursor=precursor_table[i][j]
    # print(np.array(precursor_table).shape)
    # print((i,j))
    l.debug(f'i,j={i,j}')
    # print(f'i,j={i,j}')
    if i==j:
        # print()
        print(i+1,end=" ")#let it break line
    elif precursor==None:
        print("no path from",i+1,"to",j+1,"exists")
    else:
        print_precurcer(precursor_table,i,precursor)
        print(j+1,end=" ")
#
# print_precurcer=print_precurcer_count_from_1


# 打印所有最短路径
def print_paths(precursor_table):
    n=len(precursor_table)
    for i in range(n):
        for j in range(n):
            print()
            print(f'i,j={i,j}') 
            print_precurcer(precursor_table,i,j)
            print()


print_paths(precursor_table)
# print_precurcer(precursor_table,2,0)

''' 打印最短路径权值矩阵 '''
#print_matrix(d)

相关的理论解释

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

C code:

#include "stdio.h"    
#include "stdlib.h"   

#define MAXVEX 20
#define Infinity 65535

typedef int Status;	/* Status是函数的类型,其值是函数结果状态代码,如OK等 */

typedef struct
{
	int vexs[MAXVEX];/*顶点数组*/
	int arc[MAXVEX][MAXVEX];/*边数组*/
	int numVertexes, numEdges;
}MGraph;
/*与dijkstra不同,这里用二维数组来记录
但一维也好,二维也罢,在计算机看来都是"一维"的.*/
typedef int Patharc[MAXVEX][MAXVEX];
typedef int ShortPathTable[MAXVEX][MAXVEX];

/* 构建图 */
void CreateMGraph(MGraph* G)
{
	int i, j;

	/* printf("请输入边数和顶点数:"); */
	G->numEdges = 16;
	G->numVertexes = 9;

	/*初始化顶点*/
	for (i = 0; i < G->numVertexes; i++)
	{
		G->vexs[i] = i;
	}
	/*初始化边上的权.*/
	for (i = 0; i < G->numVertexes; i++)
	{
		for (j = 0; j < G->numVertexes; j++)
		{
			if (i == j)
				G->arc[i][j] = 0;
			else
				G->arc[i][j] = G->arc[j][i] = Infinity;
		}
	}

	G->arc[0][1] = 1;
	G->arc[0][2] = 5;
	G->arc[1][2] = 3;
	G->arc[1][3] = 7;
	G->arc[1][4] = 5;

	G->arc[2][4] = 1;
	G->arc[2][5] = 7;
	G->arc[3][4] = 2;
	G->arc[3][6] = 3;
	G->arc[4][5] = 3;

	G->arc[4][6] = 6;
	G->arc[4][7] = 9;
	G->arc[5][7] = 5;
	G->arc[6][7] = 2;
	G->arc[6][8] = 7;

	G->arc[7][8] = 4;


	for (i = 0; i < G->numVertexes; i++)
	{
		for (j = i; j < G->numVertexes; j++)
		{
			G->arc[j][i] = G->arc[i][j];
		}
	}

}

/* Floyd算法,求网图G中各顶点v到其余顶点w的最短路径P[v][w]及带权长度D[v][w]。 */
void ShortestPath_Floyd(MGraph G, Patharc* P, ShortPathTable* D)
{
	int v, w, k;
	for (v = 0; v < G.numVertexes; ++v) /* 初始化D与P */
	{
		for (w = 0; w < G.numVertexes; ++w)
		{
			(*D)[v][w] = G.arc[v][w];	/* D[v][w]值即为对应点间的权值(初始化矩阵) */
			(*P)[v][w] = w;				/* 初始化P(最短路径序列的中间点(!!!保存各路径的最后一个前驱) */
		}
	}
	/*核心步骤:*/
	for (k = 0; k < G.numVertexes; ++k)   /*需要进行G.numBertexes次矩阵迭代/
										 第k个矩阵/第k个顶点开放(允许通过.)*/
	{
		/*单个矩阵的迭代需要两重循环:以遍历矩阵的所有位置(比较并迭代所有元素)*/
		for (v = 0; v < G.numVertexes; ++v)
		{
			for (w = 0; w < G.numVertexes; ++w)
			{
				/*min{,}运算(取最/较小者*/
				if ((*D)[v][w] > (*D)[v][k] + (*D)[k][w])
				{/* 如果经过下标为k的顶点的路径 比 原两点间路径更短 */
					(*D)[v][w] = (*D)[v][k] + (*D)[k][w];/* 将 当前 两点间权值 设为更小的一个 */
					
					(*P)[v][w] = (*P)[v][k];/* 路径 设置为经过 下标为k的顶点(在p矩阵的第v行第w列处修改.
											v->w的中间顶点 修改为终点是k(v->k)使所经过的中间顶点(使之保存v->w
											路径上的第一个后继)
											p数值中,不经过中间顶点(直达时)那第一个后继就是路径的终点*/
					/*注意不是:(*P)[v][w] = k 。*/
				}//if
			}//for_111


		}//for_11
		 /*可以在此处监视矩阵的修改情况:
			printf("允许通过前%d个顶点(0个表示只允许直达)的最短路径P矩阵:\n",k);
			//printf("0个表示只允许直达\n");
			for (v = 0; v < G.numVertexes; ++v)
			{
				for (w = 0; w < G.numVertexes; ++w)
				{
					printf("%d ", (*P)[v][w]);
				}
				printf("\n");
			}//for_printf
			*/

	}//for_1
}

int main(void)
{
	int v, w, k;
	MGraph G;

	Patharc P;/*保存v->w路径上的第一个后继;*/
	ShortPathTable D; /* 求某点到其余各点的最短路径 */

	CreateMGraph(&G);

	ShortestPath_Floyd(G, &P, &D);

	printf("各顶点间最短路径如下:\n");
	/*三重循环:*/
	for (v = 0; v < G.numVertexes; ++v)
	{
		for (w = v + 1; w < G.numVertexes; w++)
		{
			/*v->w的最短路径*/
			printf("v%d-v%d weight: %d ", v, w, D[v][w]);
			k = P[v][w];				/* 获得第一个路径顶点下标 */

			printf(" path: %d", v);	/* 打印源点 */
			/*顺序打印:*/
			/*比较中间点与终点w是否重合*/
			while (k != w)	/* 如果经过的中间路径顶点下标不是终点(与终点不重合) */
			{
				printf(" -> %d", k);	/* 打印途径的路径顶点 (第一个k虽然是最后更新的(如果有的话,当然也可能只在最初几次有被更新,那就可能保持着较小的数值)*/
				/*减小规模(更新中间点k),继续判断.*/
				k = P[k][w];			/* P[k][w]获得下一个路径顶点下标 */
			}


			printf(" -> %d\n", w);	/* 打印终点 */
		}
		printf("\n");
	}
	/*打印两个二维矩阵(类型的变量):D和P*/
	printf("最短路径D\n");
	for (v = 0; v < G.numVertexes; ++v)
	{
		for (w = 0; w < G.numVertexes; ++w)
		{
			printf("%d\t", D[v][w]);
		}
		printf("\n");
	}
	printf("最短路径P\n");
	for (v = 0; v < G.numVertexes; ++v)
	{
		for (w = 0; w < G.numVertexes; ++w)
		{
			printf("%d ", P[v][w]);
		}
		printf("\n");
	}

	return 0;
}

在这里插入图片描述

posted @ 2022-10-14 11:30  xuchaoxin1375  阅读(22)  评论(0)    收藏  举报  来源