1. 程式人生 > >Percolation 滲透演算法

Percolation 滲透演算法

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-