Coursera Algorithms Programming Assignment 1: Percolation
阿新 • • 發佈:2017-07-19
chain win logs generate del ech right blog spl
![技術分享](http://img.blog.csdn.net/20170717221426903?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQva2lraWNlbnRhdXI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
邊界要求: By convention, the row and column indices are integers between 1 and n, where (1, 1) is the upper-left site: Throw a java.lang.IllegalArgumentException if any argument to open(), isOpen(), or isFull() is outside its prescribed range. The constructor should throw a java.lang.IllegalArgumentException if n ≤ 0.
性能要求: The constructor should take time proportional to n2; all methods should take constant time plus a constant number of calls to the union–find methods union(), find(), connected(), and count().
題目來源http://coursera.cs.princeton.edu/algs4/assignments/percolation.html
作業分為兩部分:建立模型和仿真實驗。 最關鍵的部分就是建立模型對象。模型對象要求如下: The model. We model a percolation system using an n-by-n grid of sites. Each site is either open or blocked. A full site is an open site that can be connected to an open site in the top row via a chain of neighboring (left, right, up, down) open sites. We say the system percolates if there is a full site in the bottom row. In other words, a system percolates if we fill all open sites connected to the top row and that process fills some open site on the bottom row. (For the insulating/metallic materials example, the open sites correspond to metallic materials, so that a system that percolates has a metallic path from top to bottom, with full sites conducting. For the porous substance example, the open sites correspond to empty space through which water might flow, so that a system that percolates lets water fill open sites, flowing from top to bottom.)我的分析
本次作業根據教授在視頻課上提示,可以在grid的上方和下方各加入一個虛節點,grid第一行的open節點都與top虛節點連通,grid最後一行的open節點都與bottom虛節點連通。這樣只需判斷top虛節點與bottom虛節點是否連通就知道grid是否滲透,而不需要去一一選取特定節點比對了。照著這個思路,我實現了下述模型代碼,作業得分98。值得註意的是,模型代碼的main中測試方法不是僅僅進行各本地測試就可以了,提交作業的時候會進行自動腳本測試,所以提交的版本main方法中必須讀取args[0]中的文件名,並加載文件內容進行生成grid和open對應的site。
1 import edu.princeton.cs.algs4.In; 2 import edu.princeton.cs.algs4.StdOut; 3 import edu.princeton.cs.algs4.WeightedQuickUnionUF; 4 5 public class Percolation { 6 private static final boolean BLOCK = false; // block state 7 private static final boolean OPEN = true; // open state 8 9 /* topUF bottomUF n 均為final是因為它們只在構造函數時初始化,後續其值未發生變化 */ 10 private final WeightedQuickUnionUF topUF; // 用來記錄與top虛節點的連通性 11 private final WeightedQuickUnionUF bottomUF;// 用來記錄與bottom虛節點的連通性 12 private final int n; 13 14 private boolean[][] grid; 15 private boolean percolateFlag = false; // grid是否滲透的標誌 16 private int openedNum = 0;// 已經open的site數目 17 18 public Percolation(int n) { 19 // create n-by-n grid, with all sites blocked 20 if (n < 1) 21 throw new IllegalArgumentException("grid size should be bigger than one !"); 22 this.n = n; 23 topUF = new WeightedQuickUnionUF(n * n + 1); // 多了一個節點的空間,位置n*n處用來代表虛節點 24 bottomUF = new WeightedQuickUnionUF(n * n + 1); // 多了一個節點的空間,位置n*n處用來代表虛節點 25 grid = new boolean[n][n]; 26 // 初始化grid設為block 27 for (int i = 0; i < n; i++) 28 for (int j = 0; j < n; j++) 29 grid[i][j] = BLOCK; 30 } 31 32 private void validate(int row, int col) { 33 if (row < 1 || col < 1 || row > n || col > n) 34 throw new IllegalArgumentException("input row or col is not illegal!"); 35 } 36 37 public void open(int row, int col) { 38 // open site (row, col) if it is not open already 39 validate(row, col); 40 if (grid[row - 1][col - 1] == OPEN) 41 return; 42 43 grid[row - 1][col - 1] = OPEN; 44 openedNum++; 45 46 // n為1時,open一個節點就達到滲透要求 47 if (n == 1) { 48 topUF.union(0, 1); 49 bottomUF.union(0, 1); 50 percolateFlag = true; 51 return; 52 } 53 54 // 第一行的所有節點都與top虛節點連通 55 if (row == 1) 56 topUF.union(n * n, col - 1); 57 58 // 最後一行的所有節點都與bottom虛節點連通 59 if (row == n) 60 bottomUF.union(n * n, (n - 1) * n + col - 1); 61 62 // 與上方節點的連通性 63 if (row > 1 && grid[row - 2][col - 1] == OPEN) { 64 topUF.union((row - 2) * n + col - 1, (row - 1) * n + col - 1); 65 bottomUF.union((row - 2) * n + col - 1, (row - 1) * n + col - 1); 66 } 67 68 // 與下方節點的連通性 69 if (row < n && grid[row][col - 1] == OPEN) { 70 topUF.union(row * n + col - 1, (row - 1) * n + col - 1); 71 bottomUF.union(row * n + col - 1, (row - 1) * n + col - 1); 72 } 73 74 // 與左側節點的連通性 75 if (col > 1 && grid[row - 1][col - 2] == OPEN) { 76 topUF.union((row - 1) * n + col - 2, (row - 1) * n + col - 1); 77 bottomUF.union((row - 1) * n + col - 2, (row - 1) * n + col - 1); 78 } 79 80 // 與右側節點的連通性 81 if (col < n && grid[row - 1][col] == OPEN) { 82 topUF.union((row - 1) * n + col, (row - 1) * n + col - 1); 83 bottomUF.union((row - 1) * n + col, (row - 1) * n + col - 1); 84 } 85 86 /* 87 * 判斷條件!percolateFlag是為了防止滲透以後的重復判斷 判斷條件openedNum>=n 88 * 是因為openedNum達到n時才有可能滲透,在未達到n之前,不需要進行後續判斷 89 * 一個節點open的時候剛好使grid滲透的條件是該節點同時與top虛節點和bottom虛節點連通 90 */ 91 if (!percolateFlag && openedNum >= n && topUF.connected(n * n, (row - 1) * n + col - 1) 92 && bottomUF.connected(n * n, (row - 1) * n + col - 1)) 93 percolateFlag = true; 94 95 } 96 97 public boolean isOpen(int row, int col) { 98 // is site (row, col) open? 99 validate(row, col); 100 return grid[row - 1][col - 1] == OPEN; 101 } 102 103 /** 104 * 一個節點只有同時在open狀態並且與top虛節點連通時才是full狀態 105 * @param row 106 * @param col 107 * @return 108 */ 109 public boolean isFull(int row, int col) { 110 // is site (row, col) full? 111 validate(row, col); 112 if (isOpen(row, col) && topUF.connected(n * n, (row - 1) * n + col - 1)) 113 return true; 114 else 115 return false; 116 } 117 118 public int numberOfOpenSites() { 119 // number of open sites 120 return openedNum; 121 } 122 123 public boolean percolates() { 124 // does the system percolate? 125 return percolateFlag; 126 } 127 128 //打印一些便於查看的信息 129 private void printCheckResult(int row, int col) { 130 StdOut.println("p(" + row + "," + col + ") is open=" + isOpen(row, col) + ";is full=" + isFull(row, col) 131 + ";percolates=" + percolates()); 132 } 133 134 /** 135 * 作業提交時main需要調用該方法,因為提交後在線腳本要用一堆input文件進行測試 136 * 137 * @param arg0 138 */ 139 private static void fileInputCheck(String arg0) { 140 // test client (optional) 141 In in = new In(arg0);//讀入input文件名,並加載文件內容 142 String s = null; 143 int n = -1; 144 //讀入grid的n 145 while (in.hasNextLine()) { 146 s = in.readLine(); 147 if (s != null && !s.trim().equals("")) 148 break; 149 } 150 s = s.trim(); 151 n = Integer.parseInt(s); 152 Percolation p = new Percolation(n); 153 154 //讀入open的site坐標 155 while (in.hasNextLine()) { 156 s = in.readLine(); 157 if (s != null && !s.trim().equals("")) { 158 s = s.trim();//去掉輸入字符串頭尾空格 159 String[] sa = s.split("\\s+");//去掉中間所有空格 160 if (sa.length != 2) 161 break; 162 int row = Integer.parseInt(sa[0]); 163 int col = Integer.parseInt(sa[1]); 164 p.open(row, col); 165 } 166 } 167 168 } 169 170 /** 171 * 本地測試專用 172 */ 173 private static void generateCheck() { 174 // test client (optional) 175 Percolation p = new Percolation(3); 176 int row = 1, col = 3; 177 p.open(row, col); 178 p.printCheckResult(row, col); 179 row = 2; 180 col = 3; 181 p.open(row, col); 182 p.printCheckResult(row, col); 183 row = 3; 184 col = 3; 185 p.open(row, col); 186 p.printCheckResult(row, col); 187 row = 3; 188 col = 1; 189 p.open(row, col); 190 p.printCheckResult(row, col); 191 row = 2; 192 col = 1; 193 p.open(row, col); 194 p.printCheckResult(row, col); 195 row = 1; 196 col = 1; 197 p.open(row, col); 198 p.printCheckResult(row, col); 199 } 200 201 public static void main(String[] args) { 202 generateCheck(); 203 // fileInputCheck(args[0]); 204 } 205 }
仿真分析這一部分比較簡單,其中需要註意的地方就是“隨機選取row和col進行open”,如果簡單的用random(int n),選取[0,n)獲取row和col,會有很多重復節點被選中,隨著n越大,命中率就越低。於是我采用生成一個[0,n*n)的數組,數組內容隨機排序,依次讀取數組內容,就相當於隨機取site。
1 import edu.princeton.cs.algs4.StdOut; 2 import edu.princeton.cs.algs4.StdRandom; 3 import edu.princeton.cs.algs4.StdStats; 4 5 public class PercolationStats { 6 /* t fractions 均為final是因為它們只在構造函數時初始化,後續其值未發生變化*/ 7 private final int t;//嘗試次數 8 private final double[] fractions;//每一次嘗試的滲透率得分 9 10 private double mean; 11 private double stddev; 12 13 public PercolationStats(int n, int trials) { 14 // perform trials independent experiments on an n-by-n grid 15 if (n <= 0 || trials <= 0) 16 throw new IllegalArgumentException("n ≤ 0 or trials ≤ 0"); 17 t = trials; 18 fractions = new double[t]; 19 for (int i = 0; i < t; i++) {//t次嘗試 20 Percolation p = new Percolation(n); 21 int openNum = 0; 22 //為了實現隨機open一個site,模仿QuickUnion的定位方法 23 //先生成一個[0,n*n)的數組,數組內容隨機排序,依次讀取數組內容,就相當於隨機取site 24 int[] rand = StdRandom.permutation(n * n); 25 for (int pos : rand) { 26 //pos = (row-1)*n + col -1 27 int row = pos / n + 1; 28 int col = pos % n + 1; 29 p.open(row, col); 30 openNum++; 31 //只有openNum>=n時才有判斷是否滲透的必要 32 if (openNum >= n && p.percolates()) 33 break; 34 } 35 double pt = (double) openNum / (n * n);//單次嘗試的滲透率 36 fractions[i] = pt; 37 } 38 } 39 40 public double mean() { 41 // sample mean of percolation threshold 42 mean = StdStats.mean(fractions);//作業提交系統要求要調用一次StdStats.mean方法 43 return mean; 44 } 45 46 public double stddev() { 47 // sample standard deviation of percolation threshold 48 stddev = StdStats.stddev(fractions);//作業提交系統要求要調用一次StdStats.stddev方法 49 return stddev; 50 } 51 52 public double confidenceLo() { 53 // low endpoint of 95% confidence interval 54 return mean - 1.96 * stddev / Math.sqrt(t); 55 } 56 57 public double confidenceHi() { 58 // high endpoint of 95% confidence interval 59 return mean + 1.96 * stddev / Math.sqrt(t); 60 } 61 62 public static void main(String[] args) { 63 // test client (described below) 64 int n = Integer.parseInt(args[0]); 65 int t = Integer.parseInt(args[1]); 66 PercolationStats ps = new PercolationStats(n, t); 67 StdOut.printf("%-25s %s %f \n", "means", "=", ps.mean()); 68 StdOut.printf("%-25s %s %f \n", "stddev", "=", ps.stddev()); 69 StdOut.printf("%-25s %s%f%s%f%s\n", "95% confidence interval", "= [", ps.confidenceLo(), ", ", 70 ps.confidenceHi(), "]"); 71 } 72 }
Coursera Algorithms Programming Assignment 1: Percolation