一、名称

动态规划法应用

二、目的

1.贪婪技术的基本思想;
2.学会运用贪婪技术解决实际设计应用中碰到的问题。

三、要求

1.实现基于贪婪技术思想的Prim算法;
2.实现基于贪婪技术思想的Dijkstra算法。

四、内容

1.实现基于贪婪技术思想的Prim算法

1.1、Prim算法的伪代码描述

算法 Prim(G)
//构造最小生成树的Prim算法
//输入:加权连通图G<V,E>
//输出:E(T),组成G的最小生成树的边的集合
V(t)←{V0}  //可以用任意顶点来初始化树的顶点集合
Er←◎(集合空)
  For i←1 to |V|-1 do
在所有的边(v,u)中,求权重最小的边e*=(v*,u*),
使得v在Vt中而V-Vt中
V←VtU{u*}
Et←ErU{e*}
Return Er

2.2、Prim算法的源代码实现


package com.zyz.four;

import java.util.*;

public class Primel {
    static int MAX = Integer.MAX_VALUE;

    public static void main(String[] args) {
        int[][] map = new int[][]{
                {0, 10, MAX, MAX, MAX, 11, MAX, MAX, MAX},
                {10, 0, 18, MAX, MAX, MAX, 16, MAX, 12},
                {MAX, MAX, 0, 22, MAX, MAX, MAX, MAX, 8},
                {MAX, MAX, 22, 0, 20, MAX, MAX, 16, 21},
                {MAX, MAX, MAX, 20, 0, 26, MAX, 7, MAX},
                {11, MAX, MAX, MAX, 26, 0, 17, MAX, MAX},
                {MAX, 16, MAX, MAX, MAX, 17, 0, 19, MAX},
                {MAX, MAX, MAX, 16, 7, MAX, 19, 0, MAX},
                {MAX, 12, 8, 21, MAX, MAX, MAX, MAX, 0}};
        prim(map, map.length);
    }

    public static void prim(int[][] graph, int n) {

        char[] c = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'E', 'F'};
        int[] lowcost = new int[n];  //到新集合的最小权
        int[] mid = new int[n];//存取前驱结点
        List<Character> list = new ArrayList<Character>();//用来存储加入结点的顺序
        int i, j, min, minid, sum = 0;
        //初始化辅助数组
        for (i = 1; i < n; i++) {
            lowcost[i] = graph[0][i];
            mid[i] = 0;
        }
        list.add(c[0]);
        //一共需要加入n-1个点
        for (i = 1; i < n; i++) {
            min = MAX;
            minid = 0;
            //每次找到距离集合最近的点
            for (j = 1; j < n; j++) {
                if (lowcost[j] != 0 && lowcost[j] < min) {
                    min = lowcost[j];
                    minid = j;
                }
            }

            if (minid == 0) return;
            list.add(c[minid]);
            lowcost[minid] = 0;
            sum += min;
            System.out.println(c[mid[minid]] + "到" + c[minid] + " 权值:" + min);
            //加入该点后,更新其它点到集合的距离
            for (j = 1; j < n; j++) {
                if (lowcost[j] != 0 && lowcost[j] > graph[minid][j]) {
                    lowcost[j] = graph[minid][j];
                    mid[j] = minid;
                }
            }
        }
        System.out.println("sum:" + sum);

    }

}

2.3、Prim算法的时间效率分析

时间效率:Tn=O(n*n),在每一遍|V|-1次迭代中,就要遍历实现优先队列的数组,来查找并删除距离最小的顶点,如果有必要,在更新余下顶点的优先级。

2.实现基于贪婪技术思想的Dijkstra算法

2.1、Dijkstra算法的伪代码描述

算法 Dijkstra(G,s)
//单起点最短路径的Dijkstra算法
//输入:具非权重加权连通图G=<V,E>以及它的顶点s
//输出:对于V中的每个顶点v来说,从s到v的最短路径的长度d
//以及路径上的倒数第二个顶点Pv
Initialize(Q)//将顶点优先从队列初始化为空
For V中每一个顶点v
  dr←无穷大;Pv←null
insert(Q,v,dv)//初始化优先队列中顶点的优先级
ds←0;Decrease(Q,s,ds)//将s的优先级更新为ds
V(r) ←空集

For i←0 to |V|-1 do
  u* ←DeleteMin(Q) //删除优先级最小的元素
Vr←VrU{u*}
   For V-Vr中每一个和u*相邻的顶点u do
if du*+w(u*,u)<du
  du←du*+w(u*,u);pu du*+w(u*,u)u*
Decrease(Q,u,du)

2.2、Dijkstra算法的源代码实现

package com.zyz.four;


public class Dijkstra {
    /*
     * 参数adjMatrix:为图的权重矩阵,权值为-1的两个顶点表示不能直接相连
     * 函数功能:返回顶点0到其它所有顶点的最短距离,其中顶点0到顶点0的最短距离为0
     */
    public int[] getShortestPaths(int[][] adjMatrix) {
        int[] result = new int[adjMatrix.length];   //用于存放顶点0到其它顶点的最短距离
        boolean[] used = new boolean[adjMatrix.length];  //用于判断顶点是否被遍历
        used[0] = true;  //表示顶点0已被遍历
        for(int i = 1;i < adjMatrix.length;i++) {
            result[i] = adjMatrix[0][i];
            used[i] = false;
        }

        for(int i = 1;i < adjMatrix.length;i++) {
            int min = Integer.MAX_VALUE;    //用于暂时存放顶点0到i的最短距离,初始化为Integer型最大值
            int k = 0;
            for(int j = 1;j < adjMatrix.length;j++) {  //找到顶点0到其它顶点中距离最小的一个顶点
                if(!used[j] && result[j] != -1 && min > result[j]) {
                    min = result[j];
                    k = j;
                }
            }
            used[k] = true;    //将距离最小的顶点,记为已遍历
            for(int j = 1;j < adjMatrix.length;j++) {  //然后,将顶点0到其它顶点的距离与加入中间顶点k之后的距离进行比较,更新最短距离
                if(!used[j]) {  //当顶点j未被遍历时
                    //首先,顶点k到顶点j要能通行;这时,当顶点0到顶点j的距离大于顶点0到k再到j的距离或者顶点0无法直接到达顶点j时,更新顶点0到顶点j的最短距离
                    if(adjMatrix[k][j] != -1 && (result[j] > min + adjMatrix[k][j] || result[j] == -1))
                        result[j] = min + adjMatrix[k][j];
                }
            }
        }
        return result;
    }

    public static void main(String[] args) {
        Dijkstra test = new Dijkstra();
        int[][] adjMatrix = {{0,6,3,-1,-1,-1},
                {6,0,2,5,-1,-1},
                {3,2,0,3,4,-1},
                {-1,5,3,0,2,3},
                {-1,-1,4,2,0,5},
                {-1,-1,-1,3,5,0}};
        int[] result = test.getShortestPaths(adjMatrix);
        System.out.println("顶点0到图中所有顶点之间的最短距离为:");
        for(int i = 0;i < result.length;i++)
            System.out.print(result[i]+" ");
    }
}

2.3、Dijkstra算法的时间效率分析

Dijkstra复杂度是O(N^2),用权重矩阵表示,优先队列用无序数组来实现。

3、运行结果

3.1、Dijkstra算法的测试用例结果截图

在这里插入图片描述

3.2、Prim算法的测试用例结果截图

在这里插入图片描述

4、小结

在实验的过程中,我对贪婪技术的基本思想有了更加深入的了解。学会使用动态规划的目的,将问题从小的方面开始解决,逐步向解决整个问题靠近。通过本次实验、我了解到基于贪婪技术思想的Prim算法、Dijkstra算法基本原理。掌握了基本的使用方法、能够运用这种思路解决生活中的实际问题。

posted on 2022-08-28 22:17  热爱技术的小郑  阅读(61)  评论(0编辑  收藏  举报