节点度限制的最小生成树Primal算法的实现(JAVA)

算法参考的论文信息:
Subhash C. Narula, Cesar A. Ho,
Degree-constrained minimum spanning tree,
Computers & Operations Research,
Volume 7, Issue 4,
1980,
Pages 239-249,
ISSN 0305-0548,
https://doi.org/10.1016/0305-0548(80)90022-2.
(https://www.sciencedirect.com/science/article/pii/0305054880900222)
Abstract: In this paper the problem of a degree-constrained minimum spanning tree (DCMST) is defined. The problem is formulated as a linear 0–1 integer programming problem. A primal and a dual heuristic (construction) procedure and a branch-and-bound algorithm are proposed to construct a DCMST. These procedures are illustrated with a simple example. Some computational experience with these algorithms is also reported.

论文中相关算法的描述:

节点度限制的最小生成树Primal算法的实现(JAVA)_第1张图片
节点度限制的最小生成树Primal算法的实现(JAVA)_第2张图片

节点度限制的最小生成树Primal算法的实现(JAVA)_第3张图片

public class DCMST {
    //输出:返回n-1行,表示最小生成树的n-1条链路,2列的数组,值为节点号,表示链路两端的节点
    //输入:n:节点数;cost:代价矩阵;b:节点度限制向量
    public int[][] primal(int n, double[][] cost, int[] b) {
        /*
            Step 1. Initialize
         */
        List<Integer> F1 = new ArrayList<>();
        List<Double> F2 = new ArrayList<>();
        List<Integer> F3 = new ArrayList<>();
        List<Integer> d = new ArrayList<>();
        for (int k = 1; k <= n; k++) {
            d.add(0);
        }
        int m = 1;
        //p为1-n中的任意数
        int p = new Random().nextInt(n) + 1;
        for (int q = 1; q <= n; q++) {
            if (q == p) continue;
            F1.add(q);
            F3.add(p);
            F2.add(cost[p - 1][q - 1]);
        }
        HashSet<Integer> visited = new HashSet<>();
        int[][] E = new int[n - 1][2];

        while (true) {
            /*
                Step 2.
             */
            double c_star = Integer.MAX_VALUE;
            int i_star = 0;
            //找到F2中的最小值,将index赋值给i_star
            for (int i = 0; i < F2.size(); i++) {
                if (F2.get(i) < c_star) {
                    c_star = F2.get(i);
                    i_star = i;
                }
            }
            // r 和 s 分别对应 F3 和 F1中 i_star位置的卫星
            int r = F3.get(i_star);
            int s = F1.get(i_star);
            if (d.get(r - 1) < b[r - 1]) {
                E[m - 1][0] = r;
                E[m - 1][1] = s;
                d.set(r - 1, d.get(r - 1) + 1);
                d.set(s - 1, d.get(s - 1) + 1);
                visited.add(r);
                visited.add(s);
                /*
                    Step 4.
                */
                F1.remove(i_star);
                F2.remove(i_star);
                F3.remove(i_star);
                for (int i = 0; i < F1.size(); i++) {
                    double Gi = cost[s - 1][F1.get(i) - 1];
                    if (Gi < F2.get(i)) {
                        F2.set(i, Gi);
                        F3.set(i, s);
                    }
                }
                m = m + 1;
                if (m > n - 1) {
                    break;
                }
            } else if (d.get(r - 1) == b[r - 1]) {
                /*
                    Step 3.
                */
                for (int j = 0; j < F3.size(); j++) {
                    if (F3.get(j) == r) {
                        int t = F1.get(j);
                        double minCost = 99;
                        int u = -1;
                        for (int uu = 1; uu <= n; uu++) {
                            if (uu != t && visited.contains(uu) && d.get(uu - 1) >= 0 && d.get(uu - 1) < b[uu - 1] && cost[uu - 1][t - 1] < minCost) {
                                minCost = cost[uu - 1][t - 1];
                                u = uu;
                            }
                        }
                        if(u==-1) {
                            return new int[0][0];
                        }
                        F3.set(j, u);
                        F2.set(j, cost[t - 1][u - 1]);
                    }
                }
            }
        }

        /*
            The improvement edge exchange algorithm
        */
        unionFind u;
        for (int i = 0; i < E.length; i++) {
            int ii = E[i][0];
            int jj = E[i][1];
            u = new unionFind(n);
            for (int j = 0; j < E.length; j++) {
                if (i == j) continue;
                int x = E[j][0];
                int y = E[j][1];
                u.union(x - 1, y - 1);
            }
            int s = 0;
            List<Integer> Ti = new ArrayList<>();
            List<Integer> Tj = new ArrayList<>();
            Ti.add(s + 1);
            for (int k = 1; k < n; k++) {
                if (u.find(s) == u.find(k)) {
                    Ti.add(k + 1);
                } else {
                    Tj.add(k + 1);
                }
            }

            boolean flag = false;
            for (int v : Ti) {
                for (int w : Tj) {
                    if (cost[v - 1][w - 1] < cost[ii - 1][jj - 1] && d.get(v - 1) + 1 <= b[v - 1] && d.get(w - 1) + 1 <= b[w - 1]) {
                        E[i][0] = v;
                        E[i][1] = w;
                        d.set(v - 1, d.get(v - 1) + 1);
                        d.set(w - 1, d.get(w - 1) + 1);
                        d.set(ii - 1, d.get(ii - 1) - 1);
                        d.set(jj - 1, d.get(jj - 1) - 1);
                        flag = true;//evm exists!
                        break;
                    }
                }
                if (flag) {
                    break;
                }
            }
            if (!flag) {
                if (d.get(ii - 1) == b[ii - 1] || d.get(jj - 1) == b[jj - 1]) {
                    for (int v : Ti) {
                        for (int w : Tj) {
                            if (cost[v - 1][w - 1] == cost[ii - 1][jj - 1] && d.get(v - 1) + 1 <= b[v - 1] && d.get(w - 1) + 1 <= b[w - 1]) {
                                E[i][0] = v;
                                E[i][1] = w;
                                d.set(v - 1, d.get(v - 1) + 1);
                                d.set(w - 1, d.get(w - 1) + 1);
                                d.set(ii - 1, d.get(ii - 1) - 1);
                                d.set(jj - 1, d.get(jj - 1) - 1);
                            }
                        }
                    }
                }
            }
        }

        return E;
    }
    //使用并查集求点与点是否连通
    public class unionFind {
        int[] parent;

        public unionFind(int num) {
            parent = new int[num];
            for (int i = 0; i < num; i++) {
                parent[i] = i;
            }
        }

        public int find(int x) {
            if (x != parent[x]) {
                parent[x] = find(parent[x]);
            }
            return parent[x];
        }

        public void union(int x, int y) {
            int rootX = find(x);
            int rootY = find(y);
            if (rootX == rootY) return;
            parent[rootX] = rootY;
        }
    }

你可能感兴趣的:(科研相关,java,算法,图论)