一、题目
二、思路
1、dfs
实验要求用多种思路完成,所以一开始就沿用了上一个实验马走棋盘的思路,添加了邻接矩阵来记录有向网的权值。总体思路还是DFS遍历搜索。
过程剪枝:
1、因为要求为最短路径,而一般情况总会存在多条可行路径,在判断过程中需要走过每一条路径才能知道该路径的长度,但如果已知一条可行路径的长度,在计算另一条路径的时候,若还未完成巡回但此时路径长度已经大于已知最短可行路径,那么这条路的最终长度就必定大于已知最短路径,此时就可以不必接下去计算当前路径。
2、之前得出的路径长度可以帮助之后的路径进行快速判断,如果我们尽早得出较短的可行路径,之后的工作也会进行得更快,由剪枝1引出剪枝2,每次选择到下一点路径长度最短的点前进,这样就能较快得到较短的可行路径。
2、分支限界法
按照书本上教我们的思路来实现分支限界法,首先对邻接矩阵进行初始化,求出其的最小下界和对应的矩阵,然后以这个矩阵为根节点,开始进行类似二叉树的遍历。
在这个过程中,需要保持矩阵每行或每列都必须有一个以上的0,还需要一个函数来找出所有行中最小数中最大的。然后下一步就要决定是否走该行距离为0的点,如果选择走,就将点对应的行和列去掉,若不选择该点,则将该点置为无穷大。并比较选与不选情况下的下界变化,选择下界较小的情况继续进行递归处理,直到矩阵消失或剩下全为无穷大的不可到达点。
遇到问题:根据以上的逻辑,在实际解决过程中,出现了爆栈的情况,通过调试发现程序运行情况和书本上不一样,书本上有一些变化并没有说明清楚,那么就需要重新考虑程序的递归出口解决爆栈问题。
最后根据书上的情况得修改为一共三种递归出口判断:
1、 若剩下的全是无穷远或0(默认跳过-1即不存在的)
2、 若剩下全是无穷远
3、 若剩下全是0
若满足以上任意一种判断,可以直接得出当前下界即为最短路径。
三、复杂度分析
以DFS为主要算法,O(e+v)
时间复杂度(V边数+ E顶点数)
实际复杂度比上述要小,因为在实际中并不会完整遍历所有可行路径。
分支限界法完成比较匆忙,代码中要多次循环遍历数组,存在诸多冗余,若不急循环,程序需要的步数及为顶点数,当不断的循环判断使得复杂度难以估计。
三、实现代码
1、DFS
1 public class Sell { 2 static int[][] byGroup;// 邻接矩阵 3 static int[] visit;// 0表示未访问 1表示访问 4 static int N;// 点的个数 5 static int minstep = 10000;// 最小步数 6 7 class ToNode { 8 int n;// 第n个点 9 int L; 当前点到第n个点的距离 10 11 public ToNode(int n, int l) { 12 this.n = n; 13 this.L = l; 14 } 15 } 16 17 public static Comparator<ToNode> LComparator = new Comparator<ToNode>() { // 优先队列的比較方法(到下一点的距离近到远 18 @Override 19 public int compare(ToNode tn1, ToNode tn2) { 20 return tn1.L - tn2.L; 21 } 22 }; 23 24 public void init() { 25 Scanner sc = new Scanner(System.in); 26 System.out.println("please int N:"); 27 N = sc.nextInt(); 28 byGroup = new int[N][N]; 29 visit = new int[N]; 30 for (int i = 0; i < N; i++) { 31 for (int j = 0; j < N; j++) { 32 System.out.println("please int " + i + "-->" + j + " weight:"); 33 byGroup[i][j] = sc.nextInt(); 34 } 35 } 36 DFS(0, 0);// 从0点开始 37 } 38 39 public void DFS(int n, int step) { 40 if (visit[n] != 0 || step >= minstep) { // 当前点走过或当前已走长度大于已知最小可行长度 41 return; 42 } 43 if (step != 0) {