1. 程式人生 > >【資料結構】單源最短路徑 Dijkstra演算法

【資料結構】單源最短路徑 Dijkstra演算法

單源最短路徑問題是指:對於給定的有向網路G=(V,E),求原點V0到其他頂點的最短路徑。

按照長度遞增的順序逐步產生最短路徑的方法,稱為Dijkstra演算法。

該演算法的基本思想:

把圖中的所有頂點分成兩組,第一組包括已確定最短路徑的頂點,初始時只含有一個源點,記為集合S;第二組包括尚未確定的最短路徑的頂點,記為V-S。按最短路徑長度遞增的順序逐個把V-S中的頂點加到S中去,直至從V0出發可以到達的所有頂點都包括到S中。在這個過程中,總保持V0到第一組S各頂點的最短路金都不大於從V0到第二組V-S的任何頂點的最短路徑,第二組的頂點對應的距離是從V0到此頂點的只包括第一組S的頂點為中間頂點的最短路徑長度。對於S中任意一點j,V0到j的路徑長度皆小於V0到V-S中任意一點的路徑的長度。

個人認為的關鍵步驟:d[k]=min\begin{Bmatrix} d[k],edges[v][k]+d[v] \end{Bmatrix}

#include <stdio.h>
#include <stdlib.h>
const int FINITY = 5000;
const int M = 20;
int d[M];//最短路徑向量
int p[M];//路徑向量

typedef struct
{
	char vexs[M];//頂點資訊域
	int edges[M][M];//鄰接矩陣
	int n,e;
}Mgraph;

void creat (Mgraph *g,int c)
{
	int i,j,k,w;
	FILE *f;
	f=fopen("test.txt","r");
	if(f)
	{
		fscanf(f,"%d%d",&g->n,&g->e);
		for(i=0;i<g->n;i++)
			fscanf(f,"%1s",&g->vexs[i]);
		for(i=0;i<g->n;i++)//初始化
		{
			for(j=0;j<g->n;j++)
			{
				if(i==j)	g->edges[i][j]=0;
				else	g->edges[i][j]=FINITY;
			}
		}
		for(k=0;k<g->e;k++)
		{
			fscanf(f,"%d%d%d",&i,&j,&w);
			g->edges[i][j]=w;
			if(c==0)	g->edges[j][i]=w;
		}
		fclose(f);
	}
	else
	{
		g->n=0;
	}
}

void print(Mgraph g)
{
	int i,j;
	printf("%一共有%d個結點,%d條邊\n",g.n,g.e);
	for(i=0;i<g.n;i++)
	{
		for(j=0;j<g.n;j++)
		{
			printf("%-6d",g.edges[i][j]);
		}
		printf("\n");
	}
}

void dijkstra (Mgraph g,int v0)
{
	bool final[M];
	int i,k,v,min;
	//第一步 初始化集合S與距離向量d
	for(v=0;v<g.n;v++)
	{
		final[v]=false;
		d[v]=g.edges[v0][v];
		if(d[v]<FINITY && d[v]!=0)
			p[v]=v0;
		else
			p[v]=-1;//無前驅結點
	}
	d[v0]=0;
	final[v0]=true;
	//第二步 依次找出n-1個結點加入S中
	for(i=1;i<g.n;i++)
	{
		min=FINITY;
		for(k=0;k<g.n;k++)
		{
			if(!final[k] && d[k]<min)//!final[k] 表示k結點還在V-S中
			{
				v=k;
				min=d[k];
			}
		}
		printf("%c--%d\n",g.vexs[v],min);
		if(min==FINITY)	return ;
		final[v]=true;
		for(k=0;k<g.n;k++)
		{
			if(!final[k] && (min+g.edges[v][k])<d[k])
			{
				d[k]=min+g.edges[v][k];
				p[k]=v;
			}
		}
	}
}

void print_gpd(Mgraph g,int v0)//輸出有向圖的最短路徑
{
	int st[M],i,pre,top=-1;
	for(i=0;i<g.n;i++)
	{
		printf("%c -> %c ",g.vexs[v0],g.vexs[i]);
		printf("Distance : %3d ,path:",d[i]);
		st[++top]=i;
		pre=p[i];
		while(pre!=-1)
		{
			st[++top]=pre;
			pre=p[pre];
		}
		while(top>0)
		{
			printf("%2d",st[top--]);
		}
		printf("\n");
	}
}

int main ()
{
	int v0;
	Mgraph g;
	creat(&g,1);
	print(g);
	printf("請輸入V0:\n");
	scanf("%d",&v0);
	dijkstra (g,v0);
	print_gpd(g,v0);
	return 0;
}