图的最短路径Dijkstra+Floyed算法

/*
 *	2014-5-22
 *	摘自http://blog.csdn.net/jnu_simba/article/details/8871794
 *
*/

#include<iostream>
using namespace std;

#define MAXEDGE 20
#define MAXVEX 20
#define INFINITY 65535

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

typedef int PathArc[MAXVEX];
typedef int ShortPathTable[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];

}
/*  Dijkstra算法,求有向网G的pos顶点到其余顶点v的最短路径P[v]及带权长度D[v] */
/*  P[v]的值为前驱顶点下标,D[v]表示pos到v的最短路径长度和 */
/*  pos 取值 0~MG.numVertexs-1 */
void ShortestPath_Dijkstra(MGraph MG, int pos, PathArc P, ShortPathTable D){
    int v, w, k, min;
    int final[MAXVEX];/* final[w]=1表示求得顶点pos至w的最短路径 */



	/*初始化*/
    for (v = 0; v < MG.numVertexes; v++){
        final[v] = 0;/* 全部顶点初始化为未知最短路径状态 */
        D[v] = MG.arc[pos][v];/* 将与pos点有连线的顶点加上权值 */
        P[v] = 0;/* 初始化路径数组P为0  */
    }



    D[pos] = 0; /*说明源点pos自身的长度为0 */
    P[pos] = -1; /* -1表示自身无前驱顶点*/
    final[pos] = 1;/* pos至pos不需要求路径 */


    /* 开始主循环,每次求得pos到某个v顶点的最短路径 */
    for (v = 1; v < MG.numVertexes; v++){
        min = INFINITY;/* 当前所知离pos顶点的最近距离 */

        for (w = 0; w < MG.numVertexes; w++){	/* 寻找剩余未确认路径的节点中,离pos最近的顶点 */
            if (final[w]==0 && D[w] < min){
                k = w;
                min = D[w];		/* w顶点离pos顶点更近 */
            }
        }

        final[k] = 1;/* 将目前找到的最近的顶点置为1 */

        for (w = 0; w < MG.numVertexes; w++){/* 修正当前最短路径及距离 若D(pos->k->w)<D(w),则更新*/
            if (!final[w] && (min + MG.arc[k][w] < D[w])){
                /*  说明找到了更短的路径,修改D[w]和P[w] */
                D[w] = min + MG.arc[k][w];/* 修改当前路径长度 */
                P[w] = k;
            }
        }
    }
    /* 结束循环,若P[w] = pos;说明顶点w的前驱为pos */
}


int main(void)
{
    MGraph MG;
    PathArc P;
    ShortPathTable D;
    int i, j, pos = 0;
    CreateMGraph(&MG);
    ShortestPath_Dijkstra(MG, pos, P, D);

    cout << "逆序最短路径如下:" << endl;
    for (i = 8; i >= 0; i--)
    {
        j = i;
        while (P[j] != -1 && P[j] != 0)
        {
            cout << "v" << j << "<-" << "v" << P[j] << "  ";
            j = P[j];
        }
        cout << "v" << j << "<-" << "v" << pos << "  ";
        cout << endl;

    }
    cout << endl;

    return 0;
}
/*
逆序最短路径如下:
v8->v7  v7->v6  v6->v3  v3->v4  v4->v2  v2->v1  v1->v0
v7->v6  v6->v3  v3->v4  v4->v2  v2->v1  v1->v0
v6->v3  v3->v4  v4->v2  v2->v1  v1->v0
v5->v4  v4->v2  v2->v1  v1->v0
v4->v2  v2->v1  v1->v0
v3->v4  v4->v2  v2->v1  v1->v0
v2->v1  v1->v0
v1->v0
v0->v0
*/


D算法是求所有节点到指定节点的方法,下面的Floyed算法是求任一节点到其他所有节点的最短路径问题,问题稍微复杂点,但代码却出奇的简洁。


#include <stdio.h>


#define MAXVEX 20
#define INFINITY 65535

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



/* 构造图 */
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, int P[][MAXVEX], int D[][MAXVEX])
{    
	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)   
	{
		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];/* 路径设置为经过下标为k的顶点 */
				}
			}
		}
	}
}

int main(void)
{    
	int v,w,k;  
	MGraph G;    
	
	int P[MAXVEX][MAXVEX];    
	int D[MAXVEX][MAXVEX]; /* 求某点到其余各点的最短路径 */   
	
	CreateMGraph(&G);
	
	ShortestPath_Floyd(G,P,D);  

	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("最短路径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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值