Percolation 滲透演算法
阿新 • • 發佈:2018-12-30
Union-Find 並查集演算法
解決動態連通性一類問題的一種演算法
使用場景:
網路連線判斷
變數名等同性
社交網路
例如
實現:
Quick-find
Quick-Union
Weighted quick-union
Weighted quick-union with path compression
蒙特卡洛模擬
也稱為計算機隨機模擬方法,是一種基於”隨機數”的計算方法。特點是,可以在隨機取樣上計算得到近似結果,隨著取樣的增多,得到的結果是正確結果的概率逐漸加大
例子,蒙特卡羅方法求π。就是畫一個正方形和內切圓,隨機撒點,數一下點落在園內和正方形內的數量之比,就是二者面積之比π/4。
滲透模型
n*n 個點組成的網格,每個點是 Open 或 Closed 狀態。假如最底部的點和最頂端的點連通,就說明這個網格系統是滲透的。
比如圖中黑色表示 Closed 狀態,白色表示 Open,藍色表示與頂部連通。所以左圖是滲透的,右圖不是:
應用場景:
判斷由絕緣體和金屬材料組成的一個物體什麼情況可以導電
判斷一塊多空地形,什麼情況可以讓水或者油滲透過去
問題
假設每個點是 Open 狀態的概率是 p,計算整個系統是滲透的概率。
圖片為 20*20、100*100 網格的概率分佈:
計算方法概述
利用蒙特卡洛模擬
* 初始化 n*n 全為 Blocked 的網格系統
* 隨機 Open 一個點,重複執行,直到整個系統變成滲透的為止
* 上述過程重複 T 次,計算平均值、標準差、96% 置信區間
用 Union-Find 演算法判斷連通性
增加兩個虛擬節點,將問題簡化為判斷兩個虛擬節點之間是否連通
程式碼
Percolation.java
/******************************************************************************
* Compilation: javac-algs4 Percolation.java
* Execution: java-algs4 Percolation < input.txt
* Dependencies: None
*
* This program reads standard input.
*
* - Reads the grid size n of the percolation system.
* - Creates an n-by-n grid of sites (intially all blocked)
* - Reads in a sequence of sites (row i, column j) to open.
*
* After each site is opened, it checks if the system is percolated.
******************************************************************************/
import edu.princeton.cs.algs4.StdIn;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.WeightedQuickUnionUF;
public class Percolation {
private int gridLength;
private boolean[] grid; // true:open, false:blocked
private WeightedQuickUnionUF wqu; // with virtual top & bottom
private WeightedQuickUnionUF wqu2; // without virtual bottom
private int virtualTop;
// create n-by-n grid, with all sites blocked
public Percolation(int n) {
if (n <= 0) {
throw new IllegalArgumentException("length must be positive");
}
gridLength = n;
virtualTop = gridLength * gridLength;
grid = new boolean[virtualTop];
// the last two are virtual top & virtual bottom sites
wqu = new WeightedQuickUnionUF(virtualTop + 2);
wqu2 = new WeightedQuickUnionUF(virtualTop + 1);
}
private void validateIndecies(int row, int col) {
if (row <= 0 || row > gridLength)
throw new IndexOutOfBoundsException("row index out of bounds");
if (col <= 0 || col > gridLength)
throw new IndexOutOfBoundsException("col index out of bounds");
}
private int xyTo1D(int row, int col) {
return (row - 1) * gridLength + (col - 1);
}
// open site (row, col) if it is not open already
public void open(int row, int col) {
validateIndecies(row, col);
int self = xyTo1D(row, col);
if (grid[self]) {
return;
}
grid[self] = true;
if (row == 1) {
wqu.union(self, virtualTop);
wqu2.union(self, virtualTop);
}
if (row == gridLength) {
wqu.union(self, virtualTop + 1);
}
int other;
if (row > 1) { // up
other = xyTo1D(row - 1, col);
if (grid[other]) {
wqu.union(self, other);
wqu2.union(self, other);
}
}
if (row < gridLength) { // down
other = xyTo1D(row + 1, col);
if (grid[other]) {
wqu.union(self, other);
wqu2.union(self, other);
}
}
if (col > 1) { // left
other = xyTo1D(row, col - 1);
if (grid[other]) {
wqu.union(self, other);
wqu2.union(self, other);
}
}
if (col < gridLength) { // right
other = xyTo1D(row, col + 1);
if (grid[other]) {
wqu.union(self, other);
wqu2.union(self, other);
}
}
}
// is site (row, col) open?
public boolean isOpen(int row, int col) {
validateIndecies(row, col);
return grid[xyTo1D(row, col)];
}
// is site (row, col) full?
public boolean isFull(int row, int col) {
validateIndecies(row, col);
return wqu2.connected(virtualTop, xyTo1D(row, col));
}
// does the system percolate?
public boolean percolates() {
return wqu.connected(virtualTop, virtualTop + 1);
}
// test client (optional)
public static void main(String[] args) {
/*
Percolation percolation = new Percolation(0);
Percolation percolation = new Percolation(1);
percolation.open(0, 1);
percolation.open(1, 0);
*/
/*
Percolation percolation = new Percolation(2);
percolation.open(1, 1);
percolation.open(1, 2);
for (int i = 1; i <= 2; i++) {
for(int j = 1; j <= 2; j++) {
StdOut.println("" + percolation.isFull(i, j) + " " + percolation.isOpen(i, j));
}
}
StdOut.println("percolation is " + percolation.percolates());
*/
int n = StdIn.readInt();
Percolation percolation = new Percolation(n);
while (!StdIn.isEmpty()) {
int row = StdIn.readInt();
int col = StdIn.readInt();
percolation.open(row, col);
}
StdOut.println("percolation is " + percolation.percolates());
}
}
PercolationStats.java
/******************************************************************************
* Compilation: javac-algs4 PercolationStats.java
* Execution: java-algs4 PercolationStats length trails
* Dependencies: Percolation.java
*
* This program takes the length of grid and trails.
*
******************************************************************************/
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.StdStats;
import edu.princeton.cs.algs4.StdOut;
public class PercolationStats {
private int gridLength;
private double[] trailsResult;
private double resultMean;
private double resultStddev;
private double resultconfidenceLo;
private double resultconfidenceHi;
// perform trials independent experiments on an n-by-n grid
public PercolationStats(int n, int trials) {
if (n <= 0) {
throw new IllegalArgumentException("length must be positive");
}
if (trials <= 0) {
throw new IllegalArgumentException("trials must be positive");
}
gridLength = n;
if (gridLength == 1) {
resultMean = 1;
resultStddev = Double.NaN;
resultconfidenceLo = Double.NaN;
resultconfidenceHi = Double.NaN;
}
else {
trailsResult = new double[trials];
for (int i = 0; i < trials; i++) {
trailsResult[i] = oneTrial(gridLength);
}
resultMean = StdStats.mean(trailsResult);
resultStddev = StdStats.stddev(trailsResult);
double diff = (1.96 * resultStddev) / Math.sqrt(trials);
resultconfidenceLo = resultMean - diff;
resultconfidenceHi = resultMean + diff;
}
}
private double oneTrial(int length) {
int openedCount = 0;
Percolation percolation = new Percolation(length);
while (!percolation.percolates()) {
int row = StdRandom.uniform(length) + 1;
int col = StdRandom.uniform(length) + 1;
if (!percolation.isOpen(row, col)) {
percolation.open(row, col);
openedCount++;
}
}
return (double) openedCount / (length * length);
}
// sample mean of percolation threshold
public double mean() {
return resultMean;
}
// sample standard deviation of percolation threshold
public double stddev() {
return resultStddev;
}
// low endpoint of 95% confidence interval
public double confidenceLo() {
return resultconfidenceLo;
}
// high endpoint of 95% confidence interval
public double confidenceHi() {
return resultconfidenceHi;
}
// test client
public static void main(String[] args) {
int length = Integer.parseInt(args[0]);
int trials = Integer.parseInt(args[1]);
PercolationStats percolations = new PercolationStats(length, trials);
StdOut.println("mean = " + percolations.mean());
StdOut.println("stddev = " + percolations.stddev());
StdOut.println("95% confidence interval = "
+ percolations.confidenceLo() + ", "
+ percolations.confidenceHi());
}
}
-eof-