Percolation
Percolation.java
主要问题为backwash。其形成原因为:因为存在上下两个虚拟节点,当percolates()为true上下贯通时,所有在最底排的已经打开的节点都会变成与上虚拟节点连通(每打开一个底部节点,都会将其与下虚拟节点连通)。解决方法是再设置一个union-find,但只提供上虚拟节点,将isFull()放在第二个union-find中进行判断。
为了方便处理,将二维数组坐标转化为一维数组坐标进行处理。
import edu.princeton.cs.algs4.WeightedQuickUnionUF;
public class Percolation {
private int count; // number of open sites
private boolean[] isOpenSite;
private final int n;
private final int vTop; // the virtual top node
private final int vBottom; // the virtual bottom node
private final WeightedQuickUnionUF uf;
private final WeightedQuickUnionUF ufBW; // to avoid backwash
public Percolation(int n) {
if (n <= 0) {
throw new IllegalArgumentException();
}
count = 0;
this.n = n;
vTop = 0;
vBottom = n * n + 1;
isOpenSite = new boolean[n * n + 2];
uf = new WeightedQuickUnionUF(n * n + 2);
ufBW = new WeightedQuickUnionUF(n * n + 2);
isOpenSite[vTop] = true;
isOpenSite[vBottom] = true;
}
public boolean isOpen(int row, int col) {
check(row, col);
return isOpenSite[toIndex(row, col)];
}
public boolean isFull(int row, int col) {
check(row, col);
return ufBW.connected(vTop, toIndex(row, col));
}
public boolean percolates() {
return uf.connected(vTop, vBottom);
}
public int numberOfOpenSites() {
return count;
}
public void open(int row, int col) {
check(row, col);
int index = toIndex(row, col);
if (isOpenSite[index]) {
return;
}
isOpenSite[index] = true;
// connect the node in the first row with the virtual top node
if (row == 1) {
uf.union(index, vTop);
ufBW.union(index, vTop);
}
// connect the node in the last row with the virtual bottom node
if (row == n) {
uf.union(index, vBottom);
}
// union up
if (row >= 2 && isOpenSite[index - n]) {
uf.union(index, index - n);
ufBW.union(index, index - n);
}
// union down
if (row < n && isOpenSite[index + n]) {
uf.union(index, index + n);
ufBW.union(index, index + n);
}
// union left
if (col >= 2 && isOpenSite[index - 1]) {
uf.union(index, index - 1);
ufBW.union(index, index - 1);
}
// union right
if (col < n && isOpenSite[index + 1]) {
uf.union(index, index + 1);
ufBW.union(index, index + 1);
}
count++;
}
// change coordinate to index
private int toIndex(int i, int j) {
return (i - 1) * n + j;
}
// check if the coordinate is valid
private void check(int row, int col) {
if (row < 1 || row > n || col < 1 || col > n) {
throw new IllegalArgumentException();
}
}
}
PercolationStats.java
注意需要使用指定的API:StdStats-计算平均值和方差 StdRandom-生成随机数
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.StdStats;
public class PercolationStats {
private static final double CONFIDENCE = 1.96;
private final int n;
private final int trials;
private double[] result; // record the fraction of open sites in each trial
private double mean;
private double stddev;
private double confidenceLo;
private double confidenceHi;
public PercolationStats(int n, int trials) {
if (n <= 0 || trials <= 0) {
throw new IllegalArgumentException();
}
this.n = n;
this.trials = trials;
result = new double[trials];
this.run(); // calculate things needed after creating object
}
public double mean() {
return mean;
}
public double stddev() {
return stddev;
}
public double confidenceLo() {
return confidenceLo;
}
public double confidenceHi() {
return confidenceHi;
}
private void run() {
// calculate mean
for (int i = 0; i < trials; i++) {
result[i] = 1.0 * calOnce() / n / n;
}
mean = StdStats.mean(result);
// calculate stddev
stddev = StdStats.stddev(result);
// calculate Lo and Hi
double deviation = CONFIDENCE * stddev() / Math.sqrt(trials);
confidenceLo = mean() - deviation;
confidenceHi = mean() + deviation;
}
// calulate the number of open sites when the system percolates in one trial
private int calOnce() {
Percolation p = new Percolation(n);
while (true) {
int x = StdRandom.uniform(n) + 1;
int y = StdRandom.uniform(n) + 1;
// each site can be opened only once
if (p.isOpen(x, y)) {
continue;
}
p.open(x, y);
if (p.percolates()) {
break;
}
}
return p.numberOfOpenSites();
}
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
int trials = Integer.parseInt(args[1]);
PercolationStats ps = new PercolationStats(n, trials);
StdOut.println("mean = " + ps.mean);
StdOut.println("stddev = " + ps.stddev);
StdOut.println("95% confidence interval = [" + ps.confidenceLo + ", " + ps.confidenceHi + "]");
}
}