算法设计与分析多段图最短路径问题Word文件下载.docx

上传人:b****5 文档编号:20594388 上传时间:2023-01-24 格式:DOCX 页数:16 大小:105.05KB
下载 相关 举报
算法设计与分析多段图最短路径问题Word文件下载.docx_第1页
第1页 / 共16页
算法设计与分析多段图最短路径问题Word文件下载.docx_第2页
第2页 / 共16页
算法设计与分析多段图最短路径问题Word文件下载.docx_第3页
第3页 / 共16页
算法设计与分析多段图最短路径问题Word文件下载.docx_第4页
第4页 / 共16页
算法设计与分析多段图最短路径问题Word文件下载.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

算法设计与分析多段图最短路径问题Word文件下载.docx

《算法设计与分析多段图最短路径问题Word文件下载.docx》由会员分享,可在线阅读,更多相关《算法设计与分析多段图最短路径问题Word文件下载.docx(16页珍藏版)》请在冰豆网上搜索。

算法设计与分析多段图最短路径问题Word文件下载.docx

我们以E所有边的集合,而边的权重则由权重函数w:

E?

→?

[0,?

∞]定义。

因此,w(u,v)就是从顶点u到顶点v的非负花费值(cost)。

边的花费可以想像成两个顶点之间的距离。

任两点间路径的花费值,就是该路径上所有边的花费值总和。

已知有V中有顶点s及t,Dijkstra算法可以找到s到t的最低花费路径.?

最短路径)。

这个算法也可以在一个图中,找到从一个顶点s到任何其他顶点的最短路径。

具体算法见附录。

2.动态规划法

这里先讨论用动态规划法的解法。

考虑多段图的最短路径问题的填表形式。

用一个数组cost[n]作为存储子问题解的表格,cost[i]表示从顶点i到终点n-1的最短路径,数组path[n]存储状态,path[i]表示从顶点i到终点n-1的路径上顶点i的下一个顶点。

则:

cost[i]=min{cij+cost[j]}(i≤j≤n且顶点j是顶点i的邻接点)(式)

path[i]=j(使cij+cost[j]最小的j)(式)

对多段图的边(u,v),用cuv表示边上的权值,将从源点s到终点t的最短路径记为d(s,t),则从源点0到终点9的最短路径d(0,9)由下式确定:

d(0,9)=min{c01+d(1,9),c02+d(2,9),c03+d(3,9)},这是最后一个阶段的决策,它依赖于d(1,9)、d(2,9)和d(3,9)的计算结果,而由此模式推知,d(1,9)=min{c14+d(4,9),c15+d(5,9)},d(2,9)=min{c24+d(4,9),c25+d(5,9),c26+d(6,9)},d(3,9)=min{c35+d(5,9),c36+d(6,9)},每一个d(i,n-1)都是通过min{cik+d(k,n-1)}得到的k>

i&

&

k<

n-1;

再往后推的过程和以上的过程类似,将这些产生式得到以后,会发现他们的求解除了两点之间的代价外,在例子中,他们都依赖于d(7,9)=c79和d(8,9)=c89,而他们都是可以从图上直接得到的。

这样再从末尾一层一层往上推就可以得到最终的答案了。

算法主要由三部分组成:

第一部分是初始化部分,其时间性能为O(n);

第二部分是依次计算各个顶点到终点的最短路径,由两层嵌套的循环组成,外层循环执行n-1次,内层循环对所有出边进行计算,并且在所有循环中,每条出边只计算一次。

假定图的边数为m,则这部分的时间性能是O(m);

第三部分是输出最短路径经过的顶点,其时间性能是O(n)。

所以,算法的时间复杂性为O(n+m)。

为了实现时间的分析,在程序后添加了输出运行时间的函数,以便于对比分析。

具体算法、具体代码及实验结果见附录1。

3.分支限界法

再讨论当用分支限界法用来解决多段图路径问题的过程:

首先对该多段图应用贪心法求得近似解,并算出其代价路径。

将其作为多段图最短路径问题的上界。

而把每一段最小的代价相加,可以得到一个非常简单的下界。

于是,就可以得到了目标函数的一个大致的范围。

由于多段图将顶点划分为k个互不相交的子集,所以,多段图划分为k段,一旦某条路径的一些段被确定后,就可以并入这些信息并计算部分解的目标函数值的下界。

一般情况下,对于一个正在生成的路径,假设已经确定了i段(1≤i≤k),其路径为(r1,r2,…,ri,ri+1),此时,该部分解的目标函数值的计算方法即限界函数如下:

应用分支限界法同样求解附录中图所示多段图的最短路径问题,具体的搜索过程是这样进行的,首先考虑根节点,根据限界函数算出目标函数的值,然后下一个结点的选择在本例中有三种情况,这里每种情况下的目标函数值下界都要算出来并且加以比较,下界的计算方法为除了加上选定点与初始点之间的距离外,以后的第一个点选择一选定点为初始点到下段最小代价的路径,以后的段与段之间的代价都按他们之间最小的代价来计算。

这样再加上根节点与初始阶段之间的最小代价,就得到这种情况下的解了。

在得到的代价中,找出最小的代价,并以之为初始结点循环往下做,直到到达目标结点。

 

结论:

程序的运行截图如附录所示。

分析各个方法的整个过程得到以下思考:

1.贪心法、动态规划法和分支限界法都可以用来解决多段最短路径问题,然而在这种情况相比之下,贪心法的运算效率比较高,因为它不像另外两种方法一样,需要涉及到许多的点。

由于这里并没有找到函数有效地给程序计时(time函数很不精确,而对于小程序来说,就没有什么参考性)。

因此这里我们就以本题的数据为例,用一个笨方法,看各个方法访问了多少数据,可以看到,动态规划法由于需要填表,并有一个相关的迭代问题,它几乎涉及了所有的点;

而分支限界法,它通过贪心法设置的上下限,并以他们为依据进行剪枝,减少了许多的运算量。

而贪心法,访问了最少的点。

2.就结果准确性来看,就本题例子来看,贪心法结果为02479,路径的代价为20;

动态分配法采取的路径为:

03589,路径的代价为16;

而分支限界法,结果为03589,路径的代价为16。

可以看出,在这个方面,动态分配法和分支限界法都达到了预期的结果,相比直线,贪心法的误差就比较大了。

由以上的讨论,我们可以看出分支限界法的综合性能比较好,他和动态规划法在解决多段最短路径问题时都可以得到正确解,而贪心法虽然可以省时间与空间,但结果不准确是它的缺点。

各方法都是有利有弊的。

因此在选择方法时,还应当根据实际情况。

当只需要大概的一个解时,当然是要用省时省力的贪心法;

如果对结果又比较高的要求的话,那么就要采取动态规划法或分支限界法。

那么dijkstra算法呢,他的明显优点就是它的多用性,他可以求任意一点到其他某一点的距离,但是他访问的数据量很大,几乎要访问所有的边(相对于贪心法而言),因此这里来说,在单纯的解决多段最短路径问题时,他们的功能都差不多,而在解决其他较复杂的图时,Dijkstra算法有明显的优越性,但当然,作为贪心法的一种,他的结果的准确性不是那么的高。

Dijkstra算法在本质上为贪心算法,每一步的选择为当前步的最优,复杂度为O(n*n)。

动态规划法是可以看作是对分支限界法的改进。

分支限界算法,每一步的扩散为当前耗散度的最优,复杂度为(没算)

其实,他们各有各的优缺点,可以尝试将他们混合起来用,扬长避短,像动态规划法和分支限界法,我们是不是可以试着在动态规划法的过程中像分支限界法里一样,设置范围,并且过程中对肯定不会是最后结果的数据“剪枝”。

这样就可以提高运行速率了。

结论(必须精确、有条理、清晰与简要):

建议(直接从结论中得出):

附录

Dijstra算法(边的拓展){

While(!

(每一个d[v]==最短路径))

If(存在一条从u到v的边)

If(d[u]+w(u,v)<

d[v])

d[v]=d[u]+w(u,v);

用动态规划法解决多段图的最短路径算法为:

1.初始化:

数组cost[n]初始化为最大值,数组path[n]初始化为-1;

2.for(i=n-2;

i>

=0;

i--)

对顶点i的每一个邻接点j,根据式计算cost[i];

根据式计算path[i];

3.输出最短路径长度cost[0];

4.输出最短路径经过的顶点:

i=0

循环直到path[i]=n-1

输出path[i];

i=path[i];

用分支限界法求解多段图的最短路径问题的算法:

1.根据限界函数计算目标函数的下界down;

采用贪心法得到上界up;

2.将待处理结点表PT初始化为空;

3.for(i=1;

i<

=k;

i++)x[i]=0;

4.i=1;

u=0;

//求解第i段

5.while(i>

=1)

对顶点u的所有邻接点v

根据式计算目标函数值lb;

若lb<

=up,则将i,<

u,v>

lb存储在表PT中;

如果i==k-1且叶子结点的lb值在表PT中最小,

则输出该叶子结点对应的最优解;

否则,如果i==k-1且表PT中的叶子结点的lb值不是最小,则

up=表PT中的叶子结点最小的lb值;

将表PT中目标函数值超出up的结点删除;

u=表PT中lb最小的结点的v值;

i=表PT中lb最小的结点的i值;

i++;

动态规划法解决多段图最短路径问题:

/*多段图最短路径问题总结:

cost[i]表示从顶点i到终点n-1的最短路径,path[i]表示从顶点i到终点n-1的路径上顶点i的下一个顶点;

下面的公式重点:

cost[i]=min{c(ij)+cost[j]}

path[i]=使c(ij)+cost[j]最小的j;

c(ij)表示i和j顶点之间的距离*/

具体代码如下:

#include<

>

ctime>

#defineINFINITY32767

#defineMAX20

__int64start,end;

intmin[6],Part;

typedefstruct{

charvexs[MAX];

//顶点信息

intvexnum,arcnum;

intarcs[MAX][MAX];

//保存两个顶点之间的边长

}Graph;

//图的结构体

structnode{

intpart,node1,node2,lb,previous;

structnode*next;

};

voidCreateGraph(Graph&

G){//初始化多段图

inti,j;

start=clock();

printf("

请输入顶点数和边数:

"

);

//scanf("

%d%d"

&

;

=10;

//顶点数

=18;

//边的数

for(i=0;

i<

i++){

[i]=i;

}

for(j=0;

j<

j++)

[i][j]=INFINITY;

请按以下格式输入边的代价(顶点1顶点2两点之间边的代价,顶点标号从0开始):

\n"

for(k=0;

k++){

scanf("

%d%d%d"

i,j,[i][j]);

}

intgetDown(GraphG){//分支限界法求下界

intj,k,i,n,n0,down=0,initial[6][20];

//initial数组用来存储第i段有哪些结点

min[0]=INFINITY;

6;

20;

initial[i][j]=0;

j=0;

if[0][i]<

INFINITY){

initial[0][j++]=i;

if[0][i]<

min[0])

min[0]=[0][i];

}

Part=1;

down+=min[i];

i=0;

while(initial[i++][0]!

={

n=0;

j=0;

min[i]=INFINITY;

while(initial[i-1][j++]!

=0){

k=0;

n0=n;

while((k++)<

if[initial[i-1][j-1]][k-1]<

initial[i][n++]=k-1;

if[initial[i-1][j-1]][k-1]<

min[i])

min[i]=[initial[i-1][j-1]][k-1];

}

if(min[i]<

down+=min[i];

Part++;

returndown;

intGreedy(GraphG,intflag,intup){//贪心法

intmin=INFINITY,m=flag;

%d"

flag);

for(inti=0;

if[m][i]<

min){

min=[m][i];

flag=i;

if(flag<

{

printf("

->

up=Greedy(G,flag,up);

elseprintf("

%d\n"

returnup+min;

voidpath(GraphG,intup){//分支限界法

intdown,i,j,k,u,lb,flag=1,previous=0;

structnode*p,*end,*PT,*q,*ST,*End,*mins;

down=getDown(G);

\n若用分支限界法,该题的结果取值范围为[%d,%d]。

down,up);

PT=NULL;

end=NULL;

ST=NULL,End=NULL;

//PT用来存储合格的点,ST表用来存储由于拓展被删除的点

i=1;

u=0;

//求解第i段,u表示顶点,u是那个已确定的顶点

while(flag){

//对顶点u的所有邻接点v

//根据式计算目标函数值lb;

//若lb<

j++){//u=3,i=2

intmini=INFINITY;

//mini是用来存储选择的那个下个结点所连接的最短的路径

if(mini>

[u][j]){

for(k=0;

k++){//确定了结点以后找到由他出发最小的代价

if[j][k]<

mini)

mini=[j][k];

lb=[u][j]+mini;

for(intl=i+1;

l<

Part;

l++)

lb+=min[l];

//min[]数组存的是每段中最短的路径长度

intPrevious=previous;

intU=u;

if(U>

0){//计算lb

lb+=[Previous][U];

while(Previous!

p=PT;

while(p!

=NULL)

if(p->

node1==Previous&

p->

node2==U){

lb+=[Previous][U];

U=Previous;

Previous=p->

previous;

break;

}

}

if(lb<

=up){

structnode*p=newstructnode;

p->

part=i+1;

node1=u;

node2=j;

lb=lb;

next=NULL;

previous=previous;

printf("

%d->

%d,代价%d,上一个结点为%d\n"

p->

node1,p->

node2,p->

lb,p->

previous);

if(PT==NULL)PT=p;

elseend->

next=p;

end=p;

end->

}

q=PT;

lb=INFINITY;

while(q!

=NULL){

if(q->

lb<

lb){

mins=q;

lb=q->

lb;

q=q->

next;

}printf("

%d%dlb=%d"

mins->

node1,mins->

node2,lb);

if(p==q&

[end->

node2][]<

INFINITY){//输出该叶子结点对应的最优解

intdist=0,array[6]={0,0,0,0,0,0};

array[Part]=;

array[Part-1]=p->

node2;

array[Part-2]=p->

node1;

i=Part-3;

while(i>

array[i]=p->

i--;

q=PT;

while(q->

node2!

=array[p->

previous])

q++;

if(i>

0)

array[i-1]=q->

p=q;

printf("

最短路径为:

for(i=0;

printf("

array[i]);

if(i<

Part-1)

dist+=[i][i+1];

array[Part]);

用分支限界法得到的最短路径长度为:

dist);

flag=0;

break;

p=PT;

if(p->

node1==mins->

node1&

node2==mins->

node2){//删除PT链表中已被拓展的结点并把他添加到ST链表中

if(ST==NULL)

ST=p->

else

End->

next=p->

End=p->

End->

PT=PT->

//printf("

删除的结点是:

%d%d\n"

next->

node2);

/*else{

while(p->

next!

node2){

if(ST==NULL){

ST=p->

else{

End->

End=p->

p->

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 初中作文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1