zoukankan      html  css  js  c++  java
  • Coursera Algorithms Programming Assignment 1: Percolation(100分)

    题目来源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是否渗透,而不需要去一一选取特定节点比对了。照着这个思路,我实现了下述模型代码。值得注意的是,模型代码的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  * @author evasean www.cnblogs.com/evasean/
      6  */
      7 public class Percolation {
      8     private static final boolean BLOCK = false; // block state
      9     private static final boolean OPEN = true; // open state
     10 
     11     /* topUF bottomUF n 均为final是因为它们只在构造函数时初始化,后续其值未发生变化 */
     12     private final WeightedQuickUnionUF topUF; // 用来记录与top虚节点的连通性
     13     private final WeightedQuickUnionUF bottomUF;// 用来记录与bottom虚节点的连通性
     14     private final int n;
     15 
     16     private boolean[][] grid;
     17     private boolean percolateFlag = false; // grid是否渗透的标志
     18     private int openedNum = 0;// 已经open的site数目
     19 
     20     public Percolation(int n) {
     21         // create n-by-n grid, with all sites blocked
     22         if (n < 1)
     23             throw new IllegalArgumentException("grid size should be bigger than one !");
     24         this.n = n;
     25         topUF = new WeightedQuickUnionUF(n * n + 1); // 多了一个节点的空间,位置n*n处用来代表虚节点
     26         bottomUF = new WeightedQuickUnionUF(n * n + 1); // 多了一个节点的空间,位置n*n处用来代表虚节点
     27         grid = new boolean[n][n];
     28         // 初始化grid设为block
     29         for (int i = 0; i < n; i++)
     30             for (int j = 0; j < n; j++)
     31                 grid[i][j] = BLOCK;
     32     }
     33 
     34     private void validate(int row, int col) {
     35         if (row < 1 || col < 1 || row > n || col > n)
     36             throw new IllegalArgumentException("input row or col is not illegal!");
     37     }
     38 
     39     public void open(int row, int col) {
     40         // open site (row, col) if it is not open already
     41         validate(row, col);
     42         if (grid[row - 1][col - 1] == OPEN)
     43             return;
     44 
     45         grid[row - 1][col - 1] = OPEN;
     46         openedNum++;
     47 
     48         // n为1时,open一个节点就达到渗透要求
     49         if (n == 1) {
     50             topUF.union(0, 1);
     51             bottomUF.union(0, 1);
     52             percolateFlag = true;
     53             return;
     54         }
     55 
     56         // 第一行的所有节点都与top虚节点连通
     57         if (row == 1)
     58             topUF.union(n * n, col - 1);
     59 
     60         // 最后一行的所有节点都与bottom虚节点连通
     61         if (row == n)
     62             bottomUF.union(n * n, (n - 1) * n + col - 1);
     63 
     64         // 与上方节点的连通性
     65         if (row > 1 && grid[row - 2][col - 1] == OPEN) {
     66             topUF.union((row - 2) * n + col - 1, (row - 1) * n + col - 1);
     67             bottomUF.union((row - 2) * n + col - 1, (row - 1) * n + col - 1);
     68         }
     69 
     70         // 与下方节点的连通性
     71         if (row < n && grid[row][col - 1] == OPEN) {
     72             topUF.union(row * n + col - 1, (row - 1) * n + col - 1);
     73             bottomUF.union(row * n + col - 1, (row - 1) * n + col - 1);
     74         }
     75 
     76         // 与左侧节点的连通性
     77         if (col > 1 && grid[row - 1][col - 2] == OPEN) {
     78             topUF.union((row - 1) * n + col - 2, (row - 1) * n + col - 1);
     79             bottomUF.union((row - 1) * n + col - 2, (row - 1) * n + col - 1);
     80         }
     81 
     82         // 与右侧节点的连通性
     83         if (col < n && grid[row - 1][col] == OPEN) {
     84             topUF.union((row - 1) * n + col, (row - 1) * n + col - 1);
     85             bottomUF.union((row - 1) * n + col, (row - 1) * n + col - 1);
     86         }
     87 
     88         /*
     89          * 判断条件!percolateFlag是为了防止渗透以后的重复判断 判断条件openedNum>=n
     90          * 是因为openedNum达到n时才有可能渗透,在未达到n之前,不需要进行后续判断
     91          * 一个节点open的时候刚好使grid渗透的条件是该节点同时与top虚节点和bottom虚节点连通
     92          */
     93         if (!percolateFlag && openedNum >= n && topUF.connected(n * n, (row - 1) * n + col - 1)
     94                 && bottomUF.connected(n * n, (row - 1) * n + col - 1))
     95             percolateFlag = true;
     96 
     97     }
     98 
     99     public boolean isOpen(int row, int col) {
    100         // is site (row, col) open?
    101         validate(row, col);
    102         return grid[row - 1][col - 1] == OPEN;
    103     }
    104 
    105     /**
    106      * 一个节点只有同时在open状态并且与top虚节点连通时才是full状态
    107      * @param row
    108      * @param col
    109      * @return
    110      */
    111     public boolean isFull(int row, int col) {
    112         // is site (row, col) full?
    113         validate(row, col);
    114         if (isOpen(row, col) && topUF.connected(n * n, (row - 1) * n + col - 1))
    115             return true;
    116         else
    117             return false;
    118     }
    119 
    120     public int numberOfOpenSites() {
    121         // number of open sites
    122         return openedNum;
    123     }
    124 
    125     public boolean percolates() {
    126         // does the system percolate?
    127         return percolateFlag;
    128     }
    129 
    130     //打印一些便于查看的信息
    131     private void printCheckResult(int row, int col) {
    132         StdOut.println("p(" + row + "," + col + ") is open=" + isOpen(row, col) + ";is full=" + isFull(row, col)
    133                 + ";percolates=" + percolates());
    134     }
    135 
    136     /**
    137      * 作业提交时main需要调用该方法,因为提交后在线脚本要用一堆input文件进行测试
    138      * 
    139      * @param arg0
    140      */
    141     private static void fileInputCheck(String arg0) {
    142         // test client (optional)
    143         In in = new In(arg0);//读入input文件名,并加载文件内容
    144         String s = null;
    145         int n = -1;
    146         //读入grid的n
    147         while (in.hasNextLine()) {
    148             s = in.readLine();
    149             if (s != null && !s.trim().equals(""))
    150                 break;
    151         }
    152         s = s.trim();
    153         n = Integer.parseInt(s);
    154         Percolation p = new Percolation(n);
    155         
    156         //读入open的site坐标
    157         while (in.hasNextLine()) {
    158             s = in.readLine();
    159             if (s != null && !s.trim().equals("")) {
    160                 s = s.trim();//去掉输入字符串头尾空格
    161                 String[] sa = s.split("\s+");//去掉中间所有空格
    162                 if (sa.length != 2)
    163                     break;
    164                 int row = Integer.parseInt(sa[0]);
    165                 int col = Integer.parseInt(sa[1]);
    166                 p.open(row, col);
    167             }
    168         }
    169 
    170     }
    171 
    172     /**
    173      * 本地测试专用
    174      */
    175     private static void generateCheck() {
    176         // test client (optional)
    177         Percolation p = new Percolation(3);
    178         int row = 1, col = 3;
    179         p.open(row, col);
    180         p.printCheckResult(row, col);
    181         row = 2;
    182         col = 3;
    183         p.open(row, col);
    184         p.printCheckResult(row, col);
    185         row = 3;
    186         col = 3;
    187         p.open(row, col);
    188         p.printCheckResult(row, col);
    189         row = 3;
    190         col = 1;
    191         p.open(row, col);
    192         p.printCheckResult(row, col);
    193         row = 2;
    194         col = 1;
    195         p.open(row, col);
    196         p.printCheckResult(row, col);
    197         row = 1;
    198         col = 1;
    199         p.open(row, col);
    200         p.printCheckResult(row, col);
    201     }
    202 
    203     public static void main(String[] args) {
    204         //generateCheck();
    205         fileInputCheck(args[0]);
    206     }
    207 }

    仿真分析这一部分比较简单,其中需要注意的地方就是“随机选取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  * @author evasean www.cnblogs.com/evasean/
     6  */
     7 public class PercolationStats {
     8     /* t fractions 均为final是因为它们只在构造函数时初始化,后续其值未发生变化*/
     9     private final int t;//尝试次数
    10     private final double[] fractions;//每一次尝试的渗透率得分
    11     
    12     private double mean;
    13     private double stddev;
    14 
    15     public PercolationStats(int n, int trials) {
    16         // perform trials independent experiments on an n-by-n grid
    17         if (n <= 0 || trials <= 0)
    18             throw new IllegalArgumentException("n ≤ 0 or trials ≤ 0");
    19         t = trials;
    20         fractions = new double[t];
    21         for (int i = 0; i < t; i++) {//t次尝试
    22             Percolation p = new Percolation(n);
    23             int openNum = 0;
    24              //为了实现随机open一个site,模仿QuickUnion的定位方法
    25             //先生成一个[0,n*n)的数组,数组内容随机排序,依次读取数组内容,就相当于随机取site
    26             int[] rand = StdRandom.permutation(n * n);
    27             for (int pos : rand) {
    28                 //pos = (row-1)*n + col -1
    29                 int row = pos / n + 1; 
    30                 int col = pos % n + 1;
    31                 p.open(row, col);
    32                 openNum++;
    33                 //只有openNum>=n时才有判断是否渗透的必要
    34                 if (openNum >= n && p.percolates())
    35                     break;
    36             }
    37             double pt = (double) openNum / (n * n);//单次尝试的渗透率
    38             fractions[i] = pt;
    39         }
    40         /* 作业提交时的某个测试案例要求mean()、stddev()、confidenceLo()、confidenceHi()
    41          * 在任何时候任何次序调用的情况下都必须返回相同的值,故需要在构造函数中计算mean和stddev
    42          */
    43         //作业提交时的某个测试案例要调用一次StdStats.mean方法
    44         mean = StdStats.mean(fractions);
    45         //作业提交时的某个测试案例要求要调用一次StdStats.stddev方法
    46         stddev = StdStats.stddev(fractions);
    47     }
    48 
    49     public double mean() {
    50         // sample mean of percolation threshold
    51         return mean;
    52     }
    53 
    54     public double stddev() {
    55         // sample standard deviation of percolation threshold
    56         return stddev;
    57     }
    58 
    59     public double confidenceLo() {
    60         // low endpoint of 95% confidence interval
    61         return mean - 1.96 * stddev / Math.sqrt(t);
    62     }
    63 
    64     public double confidenceHi() {
    65         // high endpoint of 95% confidence interval
    66         return mean + 1.96 * stddev / Math.sqrt(t);
    67     }
    68 
    69     public static void main(String[] args) {
    70         // test client (described below)
    71         int n = Integer.parseInt(args[0]);
    72         int t = Integer.parseInt(args[1]);
    73         PercolationStats ps = new PercolationStats(n, t);
    74         StdOut.printf("%-25s %s %f 
    ", "means", "=", ps.mean());
    75         StdOut.printf("%-25s %s %f 
    ", "stddev", "=", ps.stddev());
    76         StdOut.printf("%-25s %s%f%s%f%s
    ", "95% confidence interval", "= [", ps.confidenceLo(), ", ",
    77                 ps.confidenceHi(), "]");
    78     }
    79 }
    本文版权归evasean所有,转载请标明出处 http://www.cnblogs.com/evasean/
  • 相关阅读:
    operator[],识别读操作和写操作
    COW写时复制
    嵌套类,PIMPL
    类型转换
    String类运算符重载,自己实现
    socket的几个配置函数
    TCP三次握手,四次挥手,状态变迁图
    运算符重载
    友元
    P4016 负载平衡问题(最小费用最大流)
  • 原文地址:https://www.cnblogs.com/evasean/p/7204501.html
Copyright © 2011-2022 走看看