1. 程式人生 > >Princeton-Algorithms-Part1-Week1-Percolation

Princeton-Algorithms-Part1-Week1-Percolation

height tro bool roo ron ima urn instance oid

技術分享圖片

技術分享圖片

Assignment specification: https://www.coursera.org/learn/algorithms-part1/programming/Lhp5z/percolation

Idea1: Virtual top and bottom sites

技術分享圖片

 1 import edu.princeton.cs.algs4.WeightedQuickUnionUF;
 2 
 3 public class Percolation {
 4     
 5     private boolean[][] sites;
 6     private int numOfOpenSites;
7 private final WeightedQuickUnionUF uf; 8 private final int n; 9 private final int top; 10 private final int bottom; 11 12 public Percolation(int n) { 13 if (n <= 0) throw new IllegalArgumentException(); 14 sites = new boolean[n][n]; 15 numOfOpenSites = 0;
16 uf = new WeightedQuickUnionUF(n * n + 2); 17 this.n = n; 18 this.top = n * n; 19 this.bottom = n * n + 1; 20 for (int i = 0; i <= n - 1; i++) uf.union(top, i); 21 for (int i = n * n - n; i <= n * n - 1; i++) uf.union(bottom, i); 22 } 23 24
public void open(int row, int col) { 25 if (isInvalidInput(row, col)) throw new IllegalArgumentException(); 26 if (isOpen(row, col)) return; 27 sites[row - 1][col - 1] = true; 28 numOfOpenSites++; 29 30 int ufIndex = convertMatrixIndexToUFIndex(row, col); 31 if (row > 1 && isOpen(row - 1, col)) { 32 uf.union(ufIndex, convertMatrixIndexToUFIndex(row - 1, col)); 33 } 34 if (row < n && isOpen(row + 1, col)) { 35 uf.union(ufIndex, convertMatrixIndexToUFIndex(row + 1, col)); 36 } 37 if (col > 1 && isOpen(row, col - 1)) { 38 uf.union(ufIndex, convertMatrixIndexToUFIndex(row, col - 1)); 39 } 40 if (col < n && isOpen(row, col + 1)) { 41 uf.union(ufIndex, convertMatrixIndexToUFIndex(row, col + 1)); 42 } 43 } 44 45 private int convertMatrixIndexToUFIndex(int row, int col) { 46 if (isInvalidInput(row, col)) throw new IllegalArgumentException(); 47 return (row - 1) * n + col - 1; 48 } 49 50 public boolean isOpen(int row, int col) { 51 if (isInvalidInput(row, col)) throw new IllegalArgumentException(); 52 return sites[row - 1][col - 1]; 53 } 54 55 public boolean isFull(int row, int col) { 56 if (isInvalidInput(row, col)) throw new IllegalArgumentException(); 57 return isOpen(row, col) 58 && uf.connected(top, convertMatrixIndexToUFIndex(row, col)); 59 } 60 61 public int numberOfOpenSites() { 62 return numOfOpenSites; 63 } 64 65 public boolean percolates() { 66 return uf.connected(top, bottom); 67 } 68 69 private boolean isInvalidInput(int row, int col) { 70 return row <= 0 || row > n || col <= 0 || col > n; 71 } 72 }

Running time:

Weighted Union-Find: connected log(n^2); find log(n^2); union log(n^2);

Percolation: open log(n^2); isOpen O(1); isFull log(n^2); numberOfOpenSites O(1); percolates log(n^2);

Memory:

Weighted Union-Find: O(n^2)

Percolation: O(n^2)

Problem:

1. Failed on cases when n equals 1.

2. Backwash problem:

技術分享圖片

Idea2: Separate virtual top from virtual bottom

Use two Union-Find, topUF(with virtual top site) and bottomUF(with virtual bottom site). The sites percolates when a open site both connect with virtual top and virtual bottom. A site is full when it connects the virtual top.

 1 import edu.princeton.cs.algs4.WeightedQuickUnionUF;
 2 
 3 public class Percolation {
 4     
 5     private boolean[][] sites;
 6     private int numOfOpenSites;
 7     private final WeightedQuickUnionUF topUF;
 8     private final WeightedQuickUnionUF bottomUF;
 9     private final int n;
10     private final int top;
11     private final int bottom;
12     private boolean isPercolate;
13         
14     public Percolation(int n) {
15         if (n <= 0) throw new IllegalArgumentException();
16         sites = new boolean[n][n];
17         numOfOpenSites = 0;
18         topUF = new WeightedQuickUnionUF(n * n + 1);
19         bottomUF = new WeightedQuickUnionUF(n * n + 1);
20         this.n = n;
21         this.top = n * n;
22         this.bottom = n * n;
23         this.isPercolate = false;
24         for (int i = 0; i <= n - 1; i++) topUF.union(top, i);
25         for (int i = n * n - n; i <= n * n - 1; i++) bottomUF.union(bottom, i);
26     }
27     
28     public void open(int row, int col) {
29         if (isInvalidInput(row, col)) throw new IllegalArgumentException();
30         if (isOpen(row, col)) return;
31         sites[row - 1][col - 1] = true;
32         numOfOpenSites++;
33         
34         int ufIndex = convertMatrixIndexToUFIndex(row, col);
35         if (row > 1 && isOpen(row - 1, col)) {
36             int up = convertMatrixIndexToUFIndex(row - 1, col);
37             topUF.union(ufIndex, up);
38             bottomUF.union(ufIndex, up);
39         }
40         if (row < n && isOpen(row + 1, col)) {
41             int down = convertMatrixIndexToUFIndex(row + 1, col);
42             topUF.union(ufIndex, down);
43             bottomUF.union(ufIndex, down);
44         }
45         if (col > 1 && isOpen(row, col - 1)) {
46             int left = convertMatrixIndexToUFIndex(row, col - 1);
47             topUF.union(ufIndex, left);
48             bottomUF.union(ufIndex, left);
49         }
50         if (col < n && isOpen(row, col + 1)) {
51             int right = convertMatrixIndexToUFIndex(row, col + 1);
52             topUF.union(ufIndex, right);
53             bottomUF.union(ufIndex, right);
54         }
55         isPercolate = isPercolate || topUF.connected(ufIndex, top) 
56             && bottomUF.connected(ufIndex, bottom);
57     }
58     
59     private int convertMatrixIndexToUFIndex(int row, int col) {
60         if (isInvalidInput(row, col)) throw new IllegalArgumentException();
61         return (row - 1) * n + col - 1;
62     }
63     
64     public boolean isOpen(int row, int col) {
65         if (isInvalidInput(row, col)) throw new IllegalArgumentException();
66         return sites[row - 1][col - 1];
67     }
68     
69     public boolean isFull(int row, int col) {
70         if (isInvalidInput(row, col)) throw new IllegalArgumentException();
71         return isOpen(row, col) 
72             && topUF.connected(top, convertMatrixIndexToUFIndex(row, col));
73     }
74     
75     public int numberOfOpenSites() {
76         return numOfOpenSites;
77     }
78     
79     public boolean percolates() {
80         return this.isPercolate;
81     }
82     
83     private boolean isInvalidInput(int row, int col) {
84         return row <= 0 || row > n || col <= 0 || col > n;
85     }
86 }

Running time:

Weighted Union-Find: connected log(n^2); find log(n^2); union log(n^2);

Percolation: open log(n^2); isOpen O(1); isFull log(n^2); numberOfOpenSites O(1); percolates log(n^2);

Memory:

Weighted Union-Find: O(n^2)

Percolation: O(n^2)

Trade-off:

Pro: Bug free; Backwash solved;

Con: Use two Union-Find instance;

Idea3: Without virtual top and bottom

Hide information in root. In int[][] sites matrix, 0000 means blocked, 0001 means opened, 0010 means connect to top, 0100 means connect to bottom. Magic happens in open() method. When try to connect the open site with its adjacent four neighbors, the root status of the new combined part is determined by those of its four neighbors. And isPercolate becomes true when the new root status equals 0111 which means both connect to top and bottom. Idea comes from: https://www.sigmainfy.com/blog/avoid-backwash-in-percolation.html

 1 import edu.princeton.cs.algs4.WeightedQuickUnionUF;
 2 
 3 public class Percolation {
 4     
 5     private int[][] sites;
 6     private int numOfOpenSites;
 7     private final WeightedQuickUnionUF uf;
 8     private final int n;
 9     private boolean isPercolate;
10         
11     public Percolation(int n) {
12         if (n <= 0) throw new IllegalArgumentException();
13         sites = new int[n][n];
14         numOfOpenSites = 0;
15         uf = new WeightedQuickUnionUF(n * n);
16         this.n = n;
17         this.isPercolate = false;
18     }
19     
20     public void open(int row, int col) {
21         if (isInvalidInput(row, col)) throw new IllegalArgumentException();
22         if (isOpen(row, col)) return;
23         numOfOpenSites++;
24         
25         int newRootStatus = 1;
26         if (row == 1) newRootStatus = newRootStatus | 2;
27         if (row == n) newRootStatus = newRootStatus | 4;
28         int ufIndex = convertMatrixIndexToUFIndex(row, col);
29         if (row > 1 && isOpen(row - 1, col)) {
30             newRootStatus = newRootStatus | findRootStatus(row - 1, col);
31             uf.union(ufIndex, convertMatrixIndexToUFIndex(row - 1, col));
32         }
33         if (row < n && isOpen(row + 1, col)) {
34             newRootStatus = newRootStatus | findRootStatus(row + 1, col);
35             uf.union(ufIndex, convertMatrixIndexToUFIndex(row + 1, col));
36         }
37         if (col > 1 && isOpen(row, col - 1)) {
38             newRootStatus = newRootStatus | findRootStatus(row, col - 1);
39             uf.union(ufIndex, convertMatrixIndexToUFIndex(row, col - 1));
40         }
41         if (col < n && isOpen(row, col + 1)) {
42             newRootStatus = newRootStatus | findRootStatus(row, col + 1);
43             uf.union(ufIndex, convertMatrixIndexToUFIndex(row, col + 1));
44         }
45         isPercolate = isPercolate || (newRootStatus & 7) == 7;
46         int newRoot = uf.find(ufIndex);
47         sites[newRoot / n][newRoot % n] = newRootStatus;
48     }
49     
50     private int convertMatrixIndexToUFIndex(int row, int col) {
51         if (isInvalidInput(row, col)) throw new IllegalArgumentException();
52         return (row - 1) * n + col - 1;
53     }
54     
55     private int findRootStatus(int row, int col) {
56         int ufIndex = convertMatrixIndexToUFIndex(row, col);
57         int rootIndex = uf.find(ufIndex);
58         return sites[rootIndex / n][rootIndex % n];
59     }
60     
61     public boolean isOpen(int row, int col) {
62         if (isInvalidInput(row, col)) throw new IllegalArgumentException();
63         return (findRootStatus(row, col) & 1) == 1;
64     }
65     
66     public boolean isFull(int row, int col) {
67         if (isInvalidInput(row, col)) throw new IllegalArgumentException();
68         return (findRootStatus(row, col) & 2) == 2;
69     }
70     
71     public int numberOfOpenSites() {
72         return numOfOpenSites;
73     }
74     
75     public boolean percolates() {
76         return this.isPercolate;
77     }
78     
79     private boolean isInvalidInput(int row, int col) {
80         return row <= 0 || row > n || col <= 0 || col > n;
81     }
82 }

Running time:

Weighted Union-Find: connected log(n^2); find log(n^2); union log(n^2);

Percolation: open log(n^2); isOpen log(n^2); isFull log(n^2); numberOfOpenSites O(1); percolates log(n^2);

Memory:

Weighted Union-Find: O(n^2)

Percolation: O(n^2)

Trade-off:

Pro: Bug free; Backwash solved; Use only one Union-Find instance;

Con: A lot of calls to UnionFind.find();

.

Princeton-Algorithms-Part1-Week1-Percolation