您的位置:首页 > 编程语言

MPI并行编程系列之五:图的单源最短路径算法

2010-04-19 09:15 316 查看
图的单源最短路径问题是指求一个从指定的顶点s到其他所有顶点i之间的最短距离。因为是从一点到其他顶点的距离,所以称谓单源。本文将介绍dijkstra算法:按路径长度递增次序的最短路径算法,并给出了对该算法MPI并行化算法。

一、算法思想

该算法的思想是:引入一个辅助向量D,它的每个分量D[i]为源顶点v到其他顶点v[i]的路径长度。初始态为:如有从v到vi的路径,则D[i]为弧[v,vi]的权值;否则D[i]为无穷大。显然

D[j]=min{D[i]}

为顶点v出发到其他顶点的一条最短路径的长度,其路径为(v,vj)。

那么下一条最短路径长度如何计算呢?其实很简单,下一条最短路径长度要么是源顶点v直接到某一顶点vk的长度,即{v,vk}。要么是源顶点v经过顶点vj到某一顶点的长度,即{v,vj,vk}。

我们假设S为已经求得最短路径的顶点的集合,那么下一条最短路径(设其终点为x),要么是弧{v,vx},要么为中间只经过S中顶点而最后到达终点X的路径。

在一般情况下,下一条最短路径的长度为:

D[j]=min{D[i]|vi属于V-S}

其中V为图顶点的集合,D[i]为弧{v,vi}的权值,或者为D[k]和弧{vk,vi}权值之和。

二、算法描述

根据以上思想,我们得到算法描述如下:

输入:图G的邻接矩阵m[0...n-1][0...n-1],源顶点v

输出:最短路径值向量D[0...n-1],最短路径矩阵p[0...n-1][0...n-2].其中D[i]为源顶点v到顶点vi的最短路径长度,向量p[i]为源顶点v到顶点vi的最短路径

1)初始化D[i]

D[i]=m[v][vi]==无穷大?无穷大:m[v][vi]

2)计算当前最短路径值

min=min{D[i]}

final[i]=1//标记顶点i已经取得最短路径

3)更新最短路径值及最短路径

for(i=0;i<n;i++)

if(!final[i])

if(D[i]>min+m[vk][vi])

D[i]=min+m[vk][vi];

endif

endif

for(j=0;j<n-1;j++)

if(p[vk][j]!=无穷大)

p[vi][j]=p[vk][j];

endif

endfor

p[vi][j]=vi

endfor

4)输出最短路径和最短路径值

三、算法实现

这里只给出算法的核心代码,如下:

voidshort_path_function(
int**matrix,
intvertex_num,
intvertex_source){
int*short_path_value;
int*final;
int*short_path_storage;
int**short_path;
intmin;
intvertex;
inti,j,k;
//分配空间
short_path_value=my_malloc(sizeof(int)*vertex_num);
final=my_malloc(sizeof(int)*vertex_num);
dynamic_allocate_matrix((void*)&short_path,(void*)&short_path_storage,vertex_num,
vertex_num-1,sizeof(int));
//初始化
for(i=0;i<vertex_num;i++){
final[i]=0;
short_path_value[i]=matrix[vertex_source][i];
//设置空路径
for(j=0;j<vertex_num-1;j++)
short_path[i][j]=-1;
//初始化路径
if(short_path_value[i]<MAX_VAULE)
short_path[i][0]=i;
}
final[vertex_source]=1;
for(i=1;i<vertex_num;i++){
//找出从源顶点出发的一条最短路径长度顶点
min=MAX_VAULE;
for(j=0;j<vertex_num;j++)
if(!final[j])
if(short_path_value[j]<min){
min=short_path_value[j];
vertex=j;
}
final[vertex]=1;
//跟新最短路径
for(j=0;j<vertex_num;j++){
if(!final[j])
if(min+matrix[vertex][j]<short_path_value[j]){
//跟新最短路径长度
short_path_value[j]=min+matrix[vertex][j];
//更新路径
k=0;
while(short_path[vertex][k]!=-1){
short_path[j][k]=short_path[vertex][k];
k++;
}
short_path[j][k]=j;
}
}
}
//打印结果
array_int_print(vertex_num,short_path_value);
print_int_matrix(short_path,vertex_num-1,vertex_num);
}

四、并行算法描述

我们对这个算法进行并行化分析,显然初始化向量D(对应于算法的第一步),更新最短路径值和最短路径(对应于算法的第三步)是可以并行化实现的,因为只要有了当前最短路径和最短路径值,各个顶点的最短路径的算法是相互独立的。在本并行化算法中,如何求得当前的最短路径和最短路径值成为关键。

我们假设一共用P个进程,图右n个顶点,我们让每个进程负责n/p个顶点,每个进程都有自己的向量D和最短路径p,我们如何求得当前的最短路径长度和最短路径呢?首先,我们可以计算出各个进程的当前最短路径,并将局部最短路径发往进程0,进程0对这些进程的最短路径进行比较,取得当前的全局最短路径,并将这一结果广播到所有的进程。

其算法描述如下:

我们假设总共有p个进程

输入:图G的邻接矩阵m[0...n-1][0...n-1],源顶点v

输出:最短路径值向量D[0...n-1],最短路径矩阵p[0...n-1][0...n-2].

1)进程0读取邻接矩阵m和源节点v,并将m,v广播到其他所有的进程

2)各进程并行初始化各自的局部D和P

3)求最短路径

1)各进程并行计算出各自的局部最短路径值,并将其发送0号进程

2)0号进程求出全局最短路径值和对应的进程号,并将其广播到其他所有的进程。

3)拥有全局最短路径值的进程将其对应的最短路径广播到其他进程(用于更新各个进程的最短路径)

4)各进程并行跟新各自的D和P

五、并行算法实现

我们这里只给出算法中第三步的具体实现:

intget_short_path_value(
int*final,
int*vertex,
int**short_path,
int*short_path_value,
int*short_path_copy,
int*shortest,
intvertex_num,
intlocal_vertex_num,
intprocess_id,
intprocess_size,
MPI_Commcomm){
intmin;
intlocal_vertex;
intshortest_process_id;
MPI_Statusstatus;
intj;
//取到每个进程的路径的最小值
min=MAX_VAULE;
for(j=0;j<local_vertex_num;j++)
if(!final[j])
if(short_path_value[j]<min){
min=short_path_value[j];
local_vertex=j;
}
//各进程将自己的最小路径值发往0号进程
if(process_id)
MPI_Send(&min,1,MPI_INT,0,DATA_MESSAGE,comm);
else{
//0号进程收集所有进程的最小值
shortest[0]=min;
for(j=1;j<process_size;j++)
MPI_Recv(shortest+j,1,MPI_INT,j,DATA_MESSAGE,comm,&status);
//0号进程计算出全局最小值,并广播到其他各个进程
min=shortest[0];
shortest_process_id=0;
for(j=1;j<process_size;j++)
if(shortest[j]<min){
min=shortest[j];
shortest_process_id=j;
}
}
//0号进程将最小值广播到所有进程,如果最小值为无穷大,则返回
MPI_Bcast(&min,1,MPI_INT,0,comm);
if(min==MAX_VAULE)
returnmin;
//0号进程将最小值所属的进程广播到所有的进程
MPI_Bcast(&shortest_process_id,1,MPI_INT,0,comm);
//拥有最小值的进程,将其对应的标志位标1,并计算该坐标的全局坐标
if(process_id==shortest_process_id){
final[local_vertex]=1;
*vertex=BLOCK_LOW(shortest_process_id,process_size,vertex_num)+local_vertex;
//复制最短路径
for(j=0;j<vertex_num-1;j++)
short_path_copy[j]=short_path[local_vertex][j];
}
//广播最短路径
MPI_Bcast(short_path_copy,vertex_num-1,MPI_INT,shortest_process_id,comm);
MPI_Bcast(vertex,1,MPI_INT,shortest_process_id,comm);
returnmin;
}

六、MPI函数说明

本并行算法用到的MPI函数主要为点对点通信函数MPI_Send和MPI_Recv,全局通信函数MPI_Bcast。MPI名字起的真好,消息传递编程,我觉得MPI算法的核心就是任务的划分和任务间的通信。

  下篇将介绍图的最下生成树及其并行算法。

[/code]
.csharpcode,.csharpcodepre
{
font-size:small;
color:black;
font-family:consolas,"CourierNew",courier,monospace;
background-color:#ffffff;
/*white-space:pre;*/
}
.csharpcodepre{margin:0em;}
.csharpcode.rem{color:#008000;}
.csharpcode.kwrd{color:#0000ff;}
.csharpcode.str{color:#006080;}
.csharpcode.op{color:#0000c0;}
.csharpcode.preproc{color:#cc6633;}
.csharpcode.asp{background-color:#ffff00;}
.csharpcode.html{color:#800000;}
.csharpcode.attr{color:#ff0000;}
.csharpcode.alt
{
background-color:#f4f4f4;
width:100%;
margin:0em;
}
.csharpcode.lnum{color:#606060;}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐
章节导航