贪心法求解单元最短路径问题

实验1. 贪心法求解单源最短路径问题

实验内容

本实验要求基于算法设计与分析的一般过程(即待求解问题的描述、算法设计、算法描述、算法正确性证明、算法分析、算法实现与测试)。应用贪心策略求解有向带权图的单源最短路径问题。

实验目的

通过本次实验,掌握算法设计与分析的一般过程,以及每个步骤的基本方法。并应用贪心法求解单源最短路径问题。

环境要求

对于环境没有特别要求。对于算法实现,可以自由选择C, C++, Java,甚至于其他程序设计语言。

Java

实验步骤

步骤1:理解问题,给出问题的描述。

步骤2:算法设计,包括策略与数据结构的选择

步骤3:描述算法。希望采用源代码以外的形式,如伪代码、流程图等;

步骤4:算法的正确性证明。需要这个环节,在理解的基础上对算法的正确性给予证明; 步骤5:算法复杂性分析,包括时间复杂性和空间复杂性;

步骤6:算法实现与测试。附上代码或以附件的形式提交,同时贴上算法运行结果截图; 步骤7:技术上、分析过程中等各种心得体会与备忘,需要言之有物。

说明:步骤1-6在“实验结果”一节中描述,步骤7在“实验总结”一节中描述。

实验结果

步骤1:给定一个有向带权图G=(V ,E ),其中每条边的权是一个非负实数。另外,给定V 中的一个顶点,称为源点。现在要计算从源点到所有其他各个顶点的最短路径长度,这里的路径长度是指路径上经过的所有边上的权值之和。这个问题通常称为单源最短路径问题。 步骤2:Dijkstra 算法思想,即先求出长度最短的一条路径,再参照它求出长度此短的一条路径,以此类推,直到从源点到其他各个顶点的最短路径全部求出为止

a :设计合适的数据结构。带权邻接矩阵C 记录结点之间的权值,数组dist 来记录从源点到其它顶点的最短路径长度,数组p 来记录最短路径;

b :初始化。令集合S={u},对于集合V-S 中的所有顶点x ,设置dist[x]=C[u][x];如果顶点i 与源点相邻,设置p[i]=u,否则p[i]=-1;

c :贪心选择结点。在集合V-S 中依照贪心策略来寻找使得dist[x]具有最小值的顶点t ,t 就是集合V-S 中距离源点u 最近的顶点

d :更新集合S 和V-S 。将顶点t 加入集合S 中,同时更新集合V-S ;

e :判断算法是否结束。如果集合V-S 为空,算法结束。否则,转步骤6;

f :对相关结点做松弛处理。对集合V-S 中的所有与顶点t 相邻的顶点x ,如dist[x]>dist[t]+C[t][x],则dist[x]=dist[t]+C[t][x]并设置p[x]=t。

步骤3:

import java.util.Scanner;

public class Theshortapproach {

private static int n;//G图中的顶点个数

private static int []distent = null;//最短路径长度

private static int []previous = null;//前驱顶点集合

public static void dijkstra(int v,int[][] a,int[] dist,int[] prev){

//单源最短路径问题的Dijkstra 算法

int n = dist.length-1; //问题的规模,0号元素未使用

if(v n) return; //源不在图中,则返回

boolean[] s = new boolean[n+1];//判断点是否在集合S 中

//初始化

for(int i = 1;i

dist[i] = a[v][i]; //源到点i 的最短特殊路径长度

s[i] = false; //点i 现在不在集合s 中

if(dist[i] == -1)

prev[i] = 0; //若最短路径长度恒为-1表示无通路,则让点i 的前驱点为0 else

prev[i] = v; //有通路则让点i 的前驱指向源

}

dist[v] = 0;

s[v] = true; //源放入集合s 中

for(int i = 1;i

int temp = Integer.MAX_VALUE;

int u = v;

//在剩下的点中除了没有通路的点中找到最容易到达的,并把最容易到达的放入u 中 for(int j = 1;j

if((!s[j])&&(dist[j]

u = j;

temp = dist[u];

}

}

s[u] = true; //u放入s 集合中

for(int j = 1;j

if((!s[j])&&(a[u][j])!= -1){

//源到点j 通过点u 的最短特殊路径长度newdist

int newdist = dist[u] + a[u][j];

if(newdist

prev[j] = u; //点j 的前驱指向点u

}

}

}

//System.out.println("从1出发到2、3、4、5的最短路径依次为:");

for(int k = 2;k

System.out.print(dist[k]+" ");

}

System.out.println(dist[n]);

}

/**

* @param args

*/

public static void main(String[] args) {

// TODO Auto-generated method stub

int v = 1;

Scanner sc = new Scanner(System.in);

String line = sc.nextLine();

n = Integer.parseInt(line);

distent=new int[n+1];

previous=new int[n+1];

int[][] a = new int[n + 1][n + 1];

for(int i=1;i

line=sc.nextLine();

String [] str=line.split(" ");

for(int j=1;j

a[i][j]=Integer.parseInt(str[j - 1]);

}

}

dijkstra(v,a,distent,previous);

int x = previous[5];

int y = previous[x];

int z = previous[y];

//System.out.println("从1到5最短路径经过的点为:");

System.out.println(z+" "+y+" "+x+" "+"5");

}

}

步骤5

算法的时间复杂度为O (n 2), 算法的空间复杂性为O (n).

步骤6

Dijkstra 算法的正确性证明。

贪心选择性质

Dijkstra 算法是应用贪心法设计策略的又一个典型例子。它所做的贪心选择是从集合V-S 中选择具有最短路径的顶点t, 从而确定从源点u 到t 的最短路径长度dist[t],这种贪心选择为什么能得到最优解呢?换句话说,为什么从源点到t 没有更短的其他路径呢?

事实上,假设存在一条从源点u 到t 且长度比dist[t]更短的路,设这条路径初次走出S 之外到达的顶点为x 属于V-S ,然后徘徊于S 内外若干次,最后离开S 到达t. 在这条路径上,分别记d(u,x),d(x,t)和d(u,t)为源点u 到顶点x, 顶点x 到顶点t 和源点u 到顶点t 的路径长度,那么,依据假设容易得出;

dist[x]

d(u,x)+d(x,t)=d(u,t)

利用边权的非负性,可知d(x,t)>=0,从而推得dist[x]

实验总结

这次实验是贪心法求单源最短路径问题,即应用贪心策略求解有向带权图的单源最短路径问题。通过这次实验,我对贪心算法有了更进一步的认识,何时用贪心算法,怎样用贪心算法有了更进一步的了解,对于有向带权图中,最短路径的求法也更熟悉,Dijkstra 算法满足贪心选择性质和最优子结构性质,在刚开始写代码时,遇到问题也很多,在舍友帮忙调试下逐渐解决。

实验1. 贪心法求解单源最短路径问题

实验内容

本实验要求基于算法设计与分析的一般过程(即待求解问题的描述、算法设计、算法描述、算法正确性证明、算法分析、算法实现与测试)。应用贪心策略求解有向带权图的单源最短路径问题。

实验目的

通过本次实验,掌握算法设计与分析的一般过程,以及每个步骤的基本方法。并应用贪心法求解单源最短路径问题。

环境要求

对于环境没有特别要求。对于算法实现,可以自由选择C, C++, Java,甚至于其他程序设计语言。

Java

实验步骤

步骤1:理解问题,给出问题的描述。

步骤2:算法设计,包括策略与数据结构的选择

步骤3:描述算法。希望采用源代码以外的形式,如伪代码、流程图等;

步骤4:算法的正确性证明。需要这个环节,在理解的基础上对算法的正确性给予证明; 步骤5:算法复杂性分析,包括时间复杂性和空间复杂性;

步骤6:算法实现与测试。附上代码或以附件的形式提交,同时贴上算法运行结果截图; 步骤7:技术上、分析过程中等各种心得体会与备忘,需要言之有物。

说明:步骤1-6在“实验结果”一节中描述,步骤7在“实验总结”一节中描述。

实验结果

步骤1:给定一个有向带权图G=(V ,E ),其中每条边的权是一个非负实数。另外,给定V 中的一个顶点,称为源点。现在要计算从源点到所有其他各个顶点的最短路径长度,这里的路径长度是指路径上经过的所有边上的权值之和。这个问题通常称为单源最短路径问题。 步骤2:Dijkstra 算法思想,即先求出长度最短的一条路径,再参照它求出长度此短的一条路径,以此类推,直到从源点到其他各个顶点的最短路径全部求出为止

a :设计合适的数据结构。带权邻接矩阵C 记录结点之间的权值,数组dist 来记录从源点到其它顶点的最短路径长度,数组p 来记录最短路径;

b :初始化。令集合S={u},对于集合V-S 中的所有顶点x ,设置dist[x]=C[u][x];如果顶点i 与源点相邻,设置p[i]=u,否则p[i]=-1;

c :贪心选择结点。在集合V-S 中依照贪心策略来寻找使得dist[x]具有最小值的顶点t ,t 就是集合V-S 中距离源点u 最近的顶点

d :更新集合S 和V-S 。将顶点t 加入集合S 中,同时更新集合V-S ;

e :判断算法是否结束。如果集合V-S 为空,算法结束。否则,转步骤6;

f :对相关结点做松弛处理。对集合V-S 中的所有与顶点t 相邻的顶点x ,如dist[x]>dist[t]+C[t][x],则dist[x]=dist[t]+C[t][x]并设置p[x]=t。

步骤3:

import java.util.Scanner;

public class Theshortapproach {

private static int n;//G图中的顶点个数

private static int []distent = null;//最短路径长度

private static int []previous = null;//前驱顶点集合

public static void dijkstra(int v,int[][] a,int[] dist,int[] prev){

//单源最短路径问题的Dijkstra 算法

int n = dist.length-1; //问题的规模,0号元素未使用

if(v n) return; //源不在图中,则返回

boolean[] s = new boolean[n+1];//判断点是否在集合S 中

//初始化

for(int i = 1;i

dist[i] = a[v][i]; //源到点i 的最短特殊路径长度

s[i] = false; //点i 现在不在集合s 中

if(dist[i] == -1)

prev[i] = 0; //若最短路径长度恒为-1表示无通路,则让点i 的前驱点为0 else

prev[i] = v; //有通路则让点i 的前驱指向源

}

dist[v] = 0;

s[v] = true; //源放入集合s 中

for(int i = 1;i

int temp = Integer.MAX_VALUE;

int u = v;

//在剩下的点中除了没有通路的点中找到最容易到达的,并把最容易到达的放入u 中 for(int j = 1;j

if((!s[j])&&(dist[j]

u = j;

temp = dist[u];

}

}

s[u] = true; //u放入s 集合中

for(int j = 1;j

if((!s[j])&&(a[u][j])!= -1){

//源到点j 通过点u 的最短特殊路径长度newdist

int newdist = dist[u] + a[u][j];

if(newdist

prev[j] = u; //点j 的前驱指向点u

}

}

}

//System.out.println("从1出发到2、3、4、5的最短路径依次为:");

for(int k = 2;k

System.out.print(dist[k]+" ");

}

System.out.println(dist[n]);

}

/**

* @param args

*/

public static void main(String[] args) {

// TODO Auto-generated method stub

int v = 1;

Scanner sc = new Scanner(System.in);

String line = sc.nextLine();

n = Integer.parseInt(line);

distent=new int[n+1];

previous=new int[n+1];

int[][] a = new int[n + 1][n + 1];

for(int i=1;i

line=sc.nextLine();

String [] str=line.split(" ");

for(int j=1;j

a[i][j]=Integer.parseInt(str[j - 1]);

}

}

dijkstra(v,a,distent,previous);

int x = previous[5];

int y = previous[x];

int z = previous[y];

//System.out.println("从1到5最短路径经过的点为:");

System.out.println(z+" "+y+" "+x+" "+"5");

}

}

步骤5

算法的时间复杂度为O (n 2), 算法的空间复杂性为O (n).

步骤6

Dijkstra 算法的正确性证明。

贪心选择性质

Dijkstra 算法是应用贪心法设计策略的又一个典型例子。它所做的贪心选择是从集合V-S 中选择具有最短路径的顶点t, 从而确定从源点u 到t 的最短路径长度dist[t],这种贪心选择为什么能得到最优解呢?换句话说,为什么从源点到t 没有更短的其他路径呢?

事实上,假设存在一条从源点u 到t 且长度比dist[t]更短的路,设这条路径初次走出S 之外到达的顶点为x 属于V-S ,然后徘徊于S 内外若干次,最后离开S 到达t. 在这条路径上,分别记d(u,x),d(x,t)和d(u,t)为源点u 到顶点x, 顶点x 到顶点t 和源点u 到顶点t 的路径长度,那么,依据假设容易得出;

dist[x]

d(u,x)+d(x,t)=d(u,t)

利用边权的非负性,可知d(x,t)>=0,从而推得dist[x]

实验总结

这次实验是贪心法求单源最短路径问题,即应用贪心策略求解有向带权图的单源最短路径问题。通过这次实验,我对贪心算法有了更进一步的认识,何时用贪心算法,怎样用贪心算法有了更进一步的了解,对于有向带权图中,最短路径的求法也更熟悉,Dijkstra 算法满足贪心选择性质和最优子结构性质,在刚开始写代码时,遇到问题也很多,在舍友帮忙调试下逐渐解决。


相关文章

  • 数学建模经典算法
  • 寻找问题的解的一种可靠的方法是首先列出所有候选解,然后依次检查每一个,在检查完所有或部分候选解后,即可找到所需要的解.理论上,当候选解数量有限并且通过检查所有或部分候选解能够得到所需解时,上述方法是可行的.不过,在实际应用中,很少使用这种方 ...查看


  • 旅行商问题
  • 1简介 "旅行商问题"常被称为"",是指一名推销员要拜访多个地点时,如何找到在拜访每个地 TSP问题 点一次后再回到起点的最短路径.规则虽然简单,但在地点数目增多后求解却极为复杂.以42个地点为例,如 ...查看


  • 2013计算机算法设计与分析期终考试复习题
  • 计算机算法设计与分析复习题 一.填空题 1.一个算法复杂性的高低体现在计算机运行该算法所需的时间和存储器资源上,因此算法的复杂性有 时间 复杂性和空间复杂性之分. 2.出自于"平衡子问题"的思想,通常分治法在分割原问题, ...查看


  • 算法设计与分析复习题目及答案
  • 分治法 1.二分搜索算法是利用( 分治策略)实现的算法. 9. 实现循环赛日程表利用的算法是(分治策略 ) 27.Strassen矩阵乘法是利用(分治策略 )实现的算法. 34.实现合并排序利用的算法是(分治策略 ). 实现大整数的乘法是利 ...查看


  • 贪心算法的应用
  • 贪心算法的应用 课程名称: 院 系: 学生姓名: 学 号: 专业班级: 指导教师: 201312-27 贪心算法的应用 摘 要:顾名思义,贪心算法总是作出在当前看来最好的选择.也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义 ...查看


  • 西安邮电大学算法资料
  • 选择: 1.算法的性质包括输入.输出.( A ).有限性. A. 确定性 B. 随机性 C. 复杂性 D. 渐近复杂性 2.备忘录法是那种算法的变形( B ). A.分治算法 B.动态规划算法 C.贪心算法 D.回溯法 3.具有最优子结构的 ...查看


  • 旅行商问题的几种求解算法比较
  • 旅行商问题的几种求解算法比较 作者: (xxx学校) 摘要:TSP问题是组合优化领域的经典问题之一,吸引了许多不同领域的研究工作者,包括数学,运筹学,物理,生物和人工智能等领域,他是目前优化领域里的热点.本文从动态规划法,分支界限法,回溯法 ...查看


  • 贪心算法思想
  • 贪心算法思想 顾名思义,贪心算法总是作出在当前看来最好的选择.也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择.当然,希望贪心算法得到的最终结果也是整体最优的.虽然贪心算法不能对所有问题都得到整体最优解,但对 ...查看


  • 计算机算法分析与设计+++论文2
  • 河北科技师范学院 欧美学院 算法设计与分析个人总结 指导教师 院 系 班 级 学生姓名 学 号 引言:对于计算机科学来说,算法分析与设计是至关重要的.在一个大型软件系统的开发中,设计出有效的算法将起到决定性的作用.通俗的讲,算法是解决问题的 ...查看


热门内容