1. 程式人生 > >Coursera Algorithms Programming Assignment 1: Percolation

Coursera Algorithms Programming Assignment 1: Percolation

chain win logs generate del ech right blog spl

題目來源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.)
技術分享技術分享 邊界要求: 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().

我的分析

本次作業根據教授在視頻課上提示,可以在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