「數據結構」普林斯頓算法課第一週作業 Algorithm I, Princeton
編程作業: Percolation
Percolation. Given a composite systems comprised of randomly distributed insulating and metallic materials: what fraction of the materials need to be metallic so that the composite system is an electrical conductor? Given a porous landscape with water on the surface (or oil below), under what conditions will the water be able to drain through to the bottom (or the oil to gush through to the surface)? Scientists have defined an abstract process known as percolation to model such situations.
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.)
思路
視頻課中已經給出了trick,就是增加虛擬頂端(virtual top site)和底端(virtual bottom site)。
因此,percolates的話只要檢查虛擬頂端和虛擬底端是否聯通即可。
增加虛擬頂端有很多方法,可以將網格變成n*(n+2)
個,也可以將網格變成n*n+2
個,方法有很多。下面代碼展示的是n*n+2
的方法,虛擬頂端直接佔用數組中index=0的項,方便了一點。
site的三種狀態:blocked
, empty open
, full open
。
另外還要注意並查集算法中的union
方法不等價於open
。
第一部分代碼展示
/* *****************************************************************************
* Name: Albert
* Date: 16 Aug.
* Description:
**************************************************************************** */
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.WeightedQuickUnionUF;
public class Percolation {
private WeightedQuickUnionUF perc;
private boolean[] flag;
private int sqrt;
private int number;
private int numberOfOpenSites;
// creates n-by-n grid, with all sites initially blocked
public Percolation(int n) {
if (n <= 0)
throw new IllegalArgumentException("n must > 0!");
sqrt = n;
number = n * n + 2;
perc = new WeightedQuickUnionUF(number);
flag = new boolean[number];
for (int i = 1; i < number - 1; i++) flag[i] = false;
flag[0] = true;
flag[number - 1] = true;
// union the virtual top site and first n sites
for (int i = 1; i <= n; i++)
perc.union(0, i);
// union the virtual bottom site and last n sites
for (int i = n * n; i > n * n - n; i--)
perc.union(n * n + 1, i);
}
// index = (row - 1) * sqrt + col
// opens the site (row, col) if it is not open already
public void open(int row, int col) {
if (row <= 0)
throw new IllegalArgumentException("row must > 0!");
if (col <= 0)
throw new IllegalArgumentException("row must > 0!");
if (flag[(row - 1) * sqrt + col] == false) {
// open sites
// up site
if (row != 1 && flag[(row - 1) * sqrt + col - sqrt])
perc.union((row - 1) * sqrt + col,
(row - 1) * sqrt + col - sqrt);
// down site
if (row != sqrt && flag[(row - 1) * sqrt + col + sqrt])
perc.union((row - 1) * sqrt + col,
(row - 1) * sqrt + col + sqrt);
// left site
if (flag[(row - 1) * sqrt + col - 1] == true && col != 1)
perc.union((row - 1) * sqrt + col,
(row - 1) * sqrt + col - 1);
// right site
if (flag[(row - 1) * sqrt + col + 1] == true && col != sqrt)
perc.union((row - 1) * sqrt + col,
(row - 1) * sqrt + col + 1);
// change flag
flag[(row - 1) * sqrt + col] = true;
// add numberofopensites
numberOfOpenSites++;
}
}
// is the site (row, col) open?
public boolean isOpen(int row, int col) {
if (row <= 0)
throw new IllegalArgumentException("row must > 0!");
if (col <= 0)
throw new IllegalArgumentException("row must > 0!");
return flag[(row - 1) * sqrt + col];
}
// is the site (row, col) full?
public boolean isFull(int row, int col) {
if (row <= 0)
throw new IllegalArgumentException("row must > 0!");
if (col <= 0)
throw new IllegalArgumentException("row must > 0!");
if (isOpen(row, col)) {
// connected(self, 0)
return perc.connected(0, (row - 1) * sqrt + col);
}
else return false;
}
// returns the number of open sites
public int numberOfOpenSites() {
return numberOfOpenSites;
}
// does the system percolate?
public boolean percolates() {
return perc.connected(0, sqrt * sqrt + 1);
}
// test client (optional)
public static void main(String[] args) {
int N = StdIn.readInt();
Percolation pe = new Percolation(N);
pe.open(1, 1);
pe.open(2, 1);
System.out.println(pe.percolates());
}
}
第二部分代碼展示
/* *****************************************************************************
* Name: Albert
* Date: 16 Aug.
* Description:
**************************************************************************** */
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.StdStats;
public class PercolationStats {
private double[] threshold;
private double[] confidence_interval;
private int T;
// perform independent trials on an n-by-n grid
public PercolationStats(int n, int trials) {
if (trials <= 0)
throw new IllegalArgumentException("Trials must > 0!");
if (n <= 0)
throw new IllegalArgumentException("n must > 0!");
T = trials;
threshold = new double[T];
int times = 0;
while (times < T) {
// each pocolation experimental
Percolation perc = new Percolation(n);
int count = 0;
// generate the x,y(less than n) to open sites
while (true) {
count++;
int x = StdRandom.uniform(n) + 1;
int y = StdRandom.uniform(n) + 1;
if (perc.isOpen(x, y)) {
continue;
}
else
perc.open(x, y);
if (perc.percolates()) break;
}
threshold[times] = (double) perc.numberOfOpenSites() / (n * n);
times++;
}
}
// sample mean of percolation threshold
public double mean() {
return StdStats.mean(threshold);
}
// sample standard deviation of percolation threshold
public double stddev() {
return StdStats.stddev(threshold);
}
// low endpoint of 95% confidence interval
public double confidenceLo() {
return (mean() - (1.96 * stddev()) / (Math.sqrt(T)));
}
// high endpoint of 95% confidence interval
public double confidenceHi() {
return (mean() + (1.96 * stddev()) / (Math.sqrt(T)));
}
// test client (see below)
public static void main(String[] args) {
PercolationStats percolationStats = new PercolationStats(200, -1);
StdOut.println(percolationStats.mean());
StdOut.println(percolationStats.stddev());
StdOut.println(percolationStats.confidenceLo());
StdOut.println(percolationStats.confidenceHi());
}
}