Minimum Spanning Tree

1. Greedy Algorithms

  Aside from Dynamic Programming, Greedy Algorithm is another kind of optimization maneuver, in which every time we make a locally optimal choice and finally get the global optimum. According to CLRS, a problem exhibits Optimal Substructure if an optimal solution to the problem contains optimal solutions to the sub-problems. A good case in point may be Huffman Coding, which generates optimal prefix code in light of the frequencies of different symbols. Here is my solution to an SJTU ACM Online Judge problem concerning such coding strategy:

 1 import java.util.*;
 2 
 3 class Huffman {
 4     private class Node {
 5         public int freq, sum;
 6         
 7         public Node(int freq,int sum) {
 8             this.freq = freq;
 9             this.sum = sum;
10         }
11     }
12     private int size, len;
13     private Node[] arr;
14     
15     public Huffman() {
16         size = 50000;
17         arr = new Node[size];
18     }
19     public void doubleSpace() {
20         Node[] tmp = arr;
21         arr = new Node[size<<1];
22         for (int i=0;i<size;i++) {
23             arr[i] = tmp[i];
24         }
25         size <<= 1;
26     }
27     public void getLeaf(int f) {
28         if (len==size) {
29             doubleSpace();
30         }
31         arr[len++] = new Node(f,0);
32     }
33     public int freqSum() {
34         // Return the weighted sum of prefix code length
35         PriorityQueue<Node> q = new PriorityQueue<Node>(len,
36                 new Comparator<Node>() {
37                     public int compare(Node a,Node b) {
38                         if (a.freq<b.freq) {
39                             return -1;
40                         } else if (a.freq>b.freq) {
41                             return 1;
42                         } else {
43                             return 0;
44                         }
45                     }
46                 }
47         );
48         for (int i=0;i<len;i++) {
49             q.add(arr[i]);
50         }
51         while (q.size()>1) {
52             Node a = q.poll(), b = q.poll();
53             q.add(new Node(a.freq+b.freq,a.freq+b.freq+a.sum+b.sum));
54         }
55         return q.peek().sum;
56     }
57 }
58 
59 public class Main {
60     public static void main(String[] args) {
61         Huffman tree = new Huffman();
62         Scanner in = new Scanner(System.in);
63         int n=in.nextInt(),tmp;
64         for (int i=0;i<n;i++) {
65             tmp = in.nextInt();
66             tree.getLeaf(tmp);
67         }
68         System.out.println(tree.freqSum());
69         in.close();
70     }
71 }

2. Prim's Algorithm

  To find a Minimal Spanning Tree of a given weighted graph, Prim's Algorithm is a greedy strategy in which we always choose an optimal vertex and connect it to the spanning tree. The following code is my solution to the USACO training problem "agrinet":

 1 import java.io.*;
 2 import java.util.*;
 3 
 4 public class agrinet {
 5     public static final int INF = 100001;
 6     public static Scanner input;
 7     public static PrintWriter output;
 8     public static int num;
 9     public static int [][] cost;
10     
11     public static int genMST() {
12         // Prim's Algorithm based on Adjacency Matrix:
13         int val=0, pos=0;
14         boolean vis[] = new boolean [num];
15         int dist[] = new int [num];
16         vis[0] = true;
17         for (int i=1;i<num;i++) {
18             dist[i] = INF;
19         }
20         for (int i=1;i<num;i++) {
21             for (int j=0;j<num;j++) {
22                 // update all the remaining vertices
23                 if (!vis[j] && dist[j]>cost[pos][j])
24                     dist[j] = cost[pos][j];
25             }
26             dist[pos] = INF;
27             for (int j=0;j<num;j++) {
28                 // search for an optimal vertex
29                 if (!vis[j] && dist[j]<dist[pos]) {
30                     pos = j;
31                 }
32             }
33             vis[pos] = true;
34             val += dist[pos];
35         }
36         return val;
37     }
38     public static void main(String[] args) throws IOException {
39         input = new Scanner(new FileReader("agrinet.in"));
40         num = input.nextInt();
41         cost = new int[num][num];
42         for (int i=0;i<num;i++) {
43             for (int j=0;j<num;j++) {
44                 cost[i][j] = input.nextInt();
45             }
46         }
47         input.close();
48         output = new PrintWriter(new FileWriter("agrinet.out"));
49         output.println(genMST());
50         output.close();
51     }
52 }


3. Kruskal's Algorithm

  Kruskal's Algorithm is another greedy method to build a Minimal Spanning Tree, in which every time we add an optimal safe edge to an edge set. Here I provide my solution an SJTU ACM Online Judge  problem as an example:

  1 import java.util.*;
  2 
  3 class DisjointSet {
  4     private int[] root;    // root of each item
  5     private int size;         // number of items
  6     
  7     public DisjointSet(int size) {
  8         if (size<=0) {
  9             throw new RuntimeException("Illegal Initial Size");
 10         } else {
 11             this.size = size;
 12             root = new int[size];
 13             for (int i=0;i<size;i++) {
 14                 root[i] = -1;
 15             }
 16         }
 17     }
 18     public void union(int i,int j) {
 19         // Merge the set of i and the set of j
 20         if (i<0||i>=size||j<0||j>=size) {
 21             throw new RuntimeException("IndexOutOfBounds on union");
 22         } else {
 23             i = find(i);
 24             j = find(j);
 25             if (i!=j) {    
 26                 // BEWARE that i and j may be identical
 27                 if (root[i]<root[j]) {
 28                     root[i] += root[j];
 29                     root[j] = i;
 30                 } else {
 31                     root[j] += root[i];
 32                     root[i] = j;
 33                 }
 34             }
 35         }
 36     }
 37     public int find(int idx)  {
 38         // Determine and return root[idx]
 39         if (idx<0||idx>=size) {
 40             throw new RuntimeException("IndexOutOfBounds on find");
 41         } else {
 42             int prev = root[idx];
 43             if (prev<0) {
 44                 return idx;
 45             } else {
 46                 root[idx] = find(prev);
 47                 return root[idx];
 48             }
 49         }
 50     }
 51 }
 52 
 53 class AdjList {
 54     private class Vert {
 55         public Edge next;
 56     }
 57     private class Edge {
 58         public int end, weight;
 59         public Edge next;
 60         
 61         public Edge(int end,int weight,Edge next) {
 62             this.end = end;
 63             this.weight = weight;
 64             this.next = next;
 65         }
 66     }
 67     private class HeapItem {
 68         public int start, end, weight;
 69         
 70         public HeapItem(int start,int end,int weight) {
 71             this.start = start;
 72             this.end = end;
 73             this.weight = weight;
 74         }
 75     }
 76     
 77     public static final int INF = 100001;
 78     private int num;
 79     private Vert [] vert;
 80     
 81     public AdjList(int num) {
 82         this.num = num;
 83         vert = new Vert[num];
 84         for (int i=0;i<num;i++) {
 85             vert[i] = new Vert();
 86         }
 87     }
 88     public void insert(int i,int j,int w) {
 89         if (i<j) {
 90             vert[i].next = new Edge(j,w,vert[i].next);
 91         } else {
 92             vert[j].next = new Edge(i,w,vert[j].next);
 93         }
 94     }
 95     public int genMST() {
 96         // Kruskal's Algorithm based on Adjacency List:
 97         DisjointSet set = new DisjointSet(num);
 98         PriorityQueue<HeapItem> q = new PriorityQueue<HeapItem>(INF,
 99                 new Comparator<HeapItem>() {
100                     public int compare(HeapItem a,HeapItem b) {
101                         if (a.weight<b.weight) {
102                             return -1;
103                         } else if (a.weight>b.weight) {
104                             return 1;
105                         } else {
106                             return 0;
107                         }
108                     }
109                 }
110         );
111         for (int i=0;i<num;i++) {
112             Edge itr = vert[i].next;
113             while (itr!=null) {
114                 q.add(new HeapItem(i,itr.end,itr.weight));
115                 itr = itr.next;
116             }
117         }
118         int cnt=0, val=0;
119         while (cnt<num-1) {
120             HeapItem e = q.poll();
121             if (set.find(e.start)!=set.find(e.end)) {
122                 set.union(e.start,e.end);
123                 val += e.weight;
124                 cnt++;
125             }
126         }
127         return val;
128     }
129 }
130 
131 public class Main {
132     public static void main(String[] args) {
133         Scanner in = new Scanner(System.in);
134         int v = in.nextInt();
135         int e = in.nextInt();
136         AdjList g = new AdjList(v);
137         for (int i=0;i<e;i++) {
138             int j = in.nextInt()-1;
139             int k = in.nextInt()-1;
140             int w = in.nextInt();
141             g.insert(j,k,w);
142         }
143         in.close();
144         System.out.println(g.genMST());
145     }
146 }


 

References:

    1. Cormen, T. H. et al. Introduction to Algorithms [M] .  北京:机械工业出版社, 2006-09

原文地址:https://www.cnblogs.com/DevinZ/p/4411434.html