弗洛伊德(Floyd)算法示例、输出最短路径方式、负值环问题

@[TOC]弗洛伊德(Floyd)算法

弗洛伊德(Floyd)算法示例、输出最短路径方式、负值环问题

弗洛伊德(Floyd)算法:在大话数据结构和浙大数据结构教材中的程序稍有不同,主要是在显示各顶点间的最短路径的方式,记录一下。

数据图:
在这里插入图片描述

代码

数组P(参考大话数据结构)、数组pf(参考浙大教材)用于记录最短路径,显示方式上:浙大教材需要用到递归程序.

负值环:Floyd算法允许负值边,不允许负值环。但下面的示例程序并不允许负值边的存在,因为例程是用无向有权图的邻接矩阵,负值边会被程序理解为两条方向相反的有向边,从而组成负值环

问题:刚开始,我把数组 pf 设置为在main中的局部变量,结果在递归程序lujing中出错,显示“Program received signal SIGSEGV”,后来改成全局变量就正常了,不知道为啥,望大佬解答一下,谢谢

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

#include "math.h"  
#include "time.h"
#include<stdbool.h> 

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXEDGE 20
#define MAXVEX 20
#define GRAPH_INFINITY 65535

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

typedef struct
{
	int vexs[MAXVEX];
	int arc[MAXVEX][MAXVEX];
	int numVertexes, numEdges;
}MGraph;

typedef int Patharc[MAXVEX][MAXVEX];
typedef int ShortPathTable[MAXVEX][MAXVEX];

Patharc pf; 

/* 构件图 */
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] = GRAPH_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]。 */    
bool 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;	
			pf[v][w]=-1;			/* 初始化P */
		}
	}
	for(k=0; k<G.numVertexes; ++k)   
	{
		for(v=0; v<G.numVertexes; ++v)  
		{        
			for(w=0; w<G.numVertexes; ++w)    
			{
				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];//(*P)[v][k];/* 路径设置为经过下标为k的顶点 */
					pf[v][w]=k;
					if(v==w && (*D)[v][w]<0) //若发现负值圈
						return false;  //不能正确解决,返回错误标记 
				}
			}
		}
	}
	return true; 
}

void lujing(int a, int b) {
	int abc = pf[a][b];
	if (abc==-1) return;
	else {
		lujing(a,abc);
		printf(" -> %d",abc);
		lujing(abc,b);
	}
}

int main(void)
{    
	int v,w,k;  
	MGraph G;    
	Patharc P;
	   
	ShortPathTable D; //* 求某点到其余各点的最短路径   
	
	CreateMGraph(&G);
	
	ShortestPath_Floyd(G,&P,&D);  
	
	
	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");
	}
	
	printf("各顶点间最短路径如下(参考大话数据结构):\n");    
	for(v=0; v<G.numVertexes; ++v)   
	{        
		for(w=v+1; w<G.numVertexes; w++)  
		{
			printf("v%d-v%d weight: %d ",v,w,D[v][w]);
			k=P[v][w];				//* 获得第一个路径顶点下标 
			printf(" path: %d",v);	//* 打印源点 
			while(k!=w)				//* 如果路径顶点下标不是终点 
			{
				printf(" -> %d",k);	//* 打印路径顶点 
				k=P[k][w];			//* 获得下一个路径顶点下标 
			}
			printf(" -> %d\n",w);	//* 打印终点 
		}
		printf("\n");
	}

	printf("最短路径pf(参考浙大教材,pf为全局变量,否则在递归中容易内存出错)\n");
	for(v=0; v<G.numVertexes; ++v)  
	{        
		for(w=0; w<G.numVertexes; ++w)    
		{
			printf("%d\t",pf[v][w]);
		}
		printf("\n");
	}
	
	printf("各顶点间最短路径如下(参考浙大教材,递归方式):\n");
	for(v=0; v<G.numVertexes; ++v) {
		for(w=v+1; w<G.numVertexes; w++) {
			printf("v%d-v%d : ",v,w);
			printf(" path: %d",v);	//* 打印开始点
			lujing(v,w);
			printf(" -> %d#\n",w);	//* 打印终止点 
		}
		printf("\n");
	}

	return 0;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值