您当前的位置:首页 > 电脑百科 > 程序开发 > 算法

什么是渗流算法?

时间:2019-08-14 10:15:24  来源:  作者:

什么是渗流(Percolation)?

渗流是物理中用来理解物理现象的一种算法,是很多物理系统的模型。

我们假设一个NxN的方形网格,其中的小网格我们叫做位(site),每个site开放(open)的概率是 1−p1−p ,site闭合(blocked)的概率是 p−1p−1 ,如果顶端(top)和底端(bottom)的site连通且能连通出一条连通路径的话,我们称这个系统是渗流(percolates)的,如下图所示。

图解:什么是渗流算法?

 

 

实际问题

专业术语往往都是晦涩难懂的,我们来看一个比较切合实际的渗流问题:

将一个不透水的均质方块分割为NxN,最上方为水源,随机打开方块中任意格子,重复此项操作多次,产生一条路径使水能穿过这个方块到达最下方。

图解:什么是渗流算法?

 

 

图解:什么是渗流算法?

 

 

上面两张图分别展示了渗流(percolates)和不渗流(not percolates)两种情况,和我们上面所说的特质相同,使用NxN的格点,每个格点site拥有open & blocked两种状态。如果最上面与最下面由open site路径连通,那么它就是渗流的。

问题分析

这个问题和之前在学习的并查集的动态连通性问题(Dynamic Connectivity)相联系,因为当open了一个site之后,这个site需要和周边的(上下左右四个方位)的site连接,类似于我们在并查集中做查询合并操作。这里我们可以用并查集相关的算法来解决。

那么随之而来的问题就是,我们如何确定最顶层和最底层是相连通的呢?这里最顶层和最底层相连通每次都是最顶层的site和最底层的site,可是这里的site是random的,是具有不确定性的。

在Coursera上的《Algorithms 4th Editon》由普林斯顿大学录制的课程中,提到了这个问题的解题思路,我们可以在最顶层与最底层再加一行,但是那一行只拥有一个site,我们如果要确定这个系统是否是渗流的通过这两个site即可确定。

图解:什么是渗流算法?

 

 

且每个site的open & blocked的状态是互相独立的,那么我们需要一个单独的容器来维护每个site的open & blocked状态。

分析完问题,直接看代码来理解会理解的更快。

Code

下面的代码都可以在我的Github仓库找到。

package net.sunzhenyu.miscellaneous.dsa.other.percolation;
import edu.princeton.cs.algs4.WeightedQuickUnionUF;
/**
 * Percolation Model
 *
 * @author <a href="mailto:sunzhenyucn@gmail.com">SunZhenyu</a>
 * @version 0.0.1
 * @date 2018/4/19
 * @since 1.8
 */
public class Percolation {
 /**
 * Initial number
 */
 private final int n;
 /**
 * Open & Blocked status array
 */
 private final boolean[] open;
 /**
 * The n * n grid
 */
 private final WeightedQuickUnionUF uf, uf2;
 /**
 * Open site count cache
 */
 private int count;
 /**
 * Constructor
 *
 * @param n create n * n grid
 * @throws IllegalArgumentException if the initial num not between 1 and n
 */
 public Percolation(int n) {
 if (n <= 0) {
 throw new IllegalArgumentException("The initial num must between 1 and " + n);
 }
 this.n = n;
 open = new boolean[n * n + 2];
 // Because we add 2 sites, so we need plus 2
 uf = new WeightedQuickUnionUF(n * n + 2);
 // Why use this?
 uf2 = new WeightedQuickUnionUF(n * n + 1);
 for (int i = 0; i < this.n; i++) {
 // The initial status is blocked
 open[i] = false;
 }
 }
 /**
 * Verify coordinate for avoid {@link IllegalArgumentException}
 *
 * @param row coordinate
 * @param col coordinate
 * @throws IllegalArgumentException if coordinate not between one and {@code n}
 */
 private void outBoundsCheck(int row, int col) {
 if (row <= 0 || row > n || col <= 0 || col > n) {
 throw new IllegalArgumentException(
 "The coordinate must be [1, n], please check your coordinate");
 }
 }
 /**
 * Transfer coordinate to array index
 *
 * @param row coordinate
 * @param col coordinate
 * @return array index of coordinate
 */
 private int index(int row, int col) {
 outBoundsCheck(row, col);
 return (row - 1) * n + col;
 }
 /**
 * Check specified coordinate's site is open
 *
 * @param row coordinate
 * @param col coordinate
 * @return if open return true
 */
 public boolean isOpen(int row, int col) {
 outBoundsCheck(row, col);
 return open[index(row, col)];
 }
 /**
 * Check specified coordinate's site is full
 *
 * @param row coordinate
 * @param col coordinate
 * @return if full return true
 */
 public boolean isFull(int row, int col) {
 outBoundsCheck(row, col);
 if (!isOpen(row, col)) {
 return false;
 }
 return uf2.connected(index(row, col), 0);
 }
 /**
 * Return this percolate model's open site count
 *
 * @return this percolate model's open site count
 */
 public int numberOfOpenSites() {
 return count;
 }
 /**
 * Return this percolate model's percolates status
 *
 * @return this percolate model's percolates status
 */
 public boolean percolates() {
 return uf.connected(0, n * n + 1);
 }
 /**
 * Open specified coordinate's site and neighborhood's site if they are not open already
 *
 * @param row coordinate
 * @param col coordinate
 */
 public void open(int row, int col) {
 outBoundsCheck(row, col);
 if (isOpen(row, col)) {
 return;
 }
 //Open this site
 open[index(row, col)] = true;
 // Top
 if (row == 1) {
 open[0] = true;
 uf.union(index(row, col), 0);
 uf2.union(index(row, col), 0);
 }
 // Bottom
 if (row == n) {
 open[n * n + 1] = true;
 uf.union(index(row, col), n * n + 1);
 }
 // Up
 if (row > 1 && isOpen(row - 1, col)) {
 uf.union(index(row, col), index(row - 1, col));
 uf2.union(index(row, col), index(row - 1, col));
 }
 // Down
 if (row < n && isOpen(row + 1, col)) {
 uf.union(index(row, col), index(row + 1, col));
 uf2.union(index(row, col), index(row + 1, col));
 }
 // Left
 if (col > 1 && isOpen(row, col - 1)) {
 uf.union(index(row, col), index(row, col - 1));
 uf2.union(index(row, col), index(row, col - 1));
 }
 // Right
 if (col < n && isOpen(row, col + 1)) {
 uf.union(index(row, col), index(row, col + 1));
 uf2.union(index(row, col), index(row, col + 1));
 }
 // Increment open count
 count++;
 }
 public static void main(String[] args) {
 int n = 3;
 Percolation p = new Percolation(n);
// while (!p.percolates()) {
// int i = StdRandom.uniform(1, n + 1);
// int j = StdRandom.uniform(1, n + 1);
// if (!p.isOpen(i, j)) {
// p.open(i, j);
// System.out.println("open (" + i + "," + j + "), isFull::" + p.isFull(i, j));
// }
// }
 p.open(2, 1);
 System.out.println(p.isOpen(1, 1));
 System.out.println(p.isOpen(1, 1));
 System.out.println(p.isFull(1, 1));
 }
}

 

下面我们来说一下为什么需要两个WeightedQuickUnionUF。

Backwash

我们使用虚拟顶点与虚拟底点的方式来解决对系统是否渗流的判断问题,从而引出了一个新的问题,那就是Backwash。

为什么会出现这样的情况呢?因为有的site只与最底层连通,而没有连通至最高层的site,但在并查集的数据结构中确实显示能够与顶层的site连通,从而被标记成了full的状态。

图解:什么是渗流算法?

 

 

那么要解决这个问题,就需要另一个WeightedQuickUnionUF,这个不包含虚拟底点,这样在isFull()方法中检查的时候就不会出现这种问题了。

蒙特卡洛模拟

蒙特卡罗方法(英语:Monte Carlo method),也称统计模拟方法,是1940年代中期由于科学技术的发展和电子计算机的发明,而提出的一种以概率统计理论为指导的数值计算方法。是指使用随机数(或更常见的伪随机数)来解决很多计算问题的方法。摘自Wikipedia 蒙特卡洛方法 词条

通俗理解就是通过大量地随机样本,进而得到目标问题的所要计算的值。

在本题中,用来估计渗滤阈值。设定网格中所有方格为阻塞状态,随机打开一个方格后,判断该系统是否渗滤,如果没有,则继续打开,直到系统渗滤。那么$p$就为打开的方格数除以所有的方格数。进行大量多次实验就可以估计$p$的值。

package net.sunzhenyu.miscellaneous.dsa.other.percolation;
import edu.princeton.cs.algs4.StdOut;
import edu.princeton.cs.algs4.StdRandom;
import edu.princeton.cs.algs4.StdStats;
/**
 * Percolation Monte Monte Carlo simulation
 *
 * @author <a href="mailto:sunzhenyucn@gmail.com">SunZhenyu</a>
 * @version 0.0.1
 * @date 2018/4/19
 * @since 1.8
 */
public class PercolationStats {
 private static final double NUM = 1.96;
 private int t;
 private double[] fraction;
 public PercolationStats(int n, int t) { // perform t independent experiments on an n-by-n grid
 if (n <= 0 || t <= 0) {
 throw new IllegalArgumentException("n and t must be bigger than 0");
 }
 this.t = t;
 fraction = new double[t];
 for (int count = 0; count < t; count++) {
 Percolation pr = new Percolation(n);
 int openedSites = 0;
 while (!pr.percolates()) {
 int i = StdRandom.uniform(1, n + 1);
 int j = StdRandom.uniform(1, n + 1);
 if (!pr.isOpen(i, j)) {
 pr.open(i, j);
 openedSites++;
 }
 }
 fraction[count] = (double) openedSites / (n * n);
 }
 }
 public double mean() { // sample mean of percolation threshold
 return StdStats.mean(fraction);
 }
 public double stddev() { // sample standard deviation of percolation threshold
 return StdStats.stddev(fraction);
 }
 public double confidenceLo() { // low endpoint of 95% confidence interval
 return mean() - NUM * stddev() / Math.sqrt(t);
 }
 public double confidenceHi() { // high endpoint of 95% confidence interval
 return mean() + NUM * stddev() / Math.sqrt(t);
 }
 public static void main(String[] args) // test client (described below)
{
 int n = Integer.parseInt(args[0]);
 int t = Integer.parseInt(args[1]);
 PercolationStats ps = new PercolationStats(n, t);
 StdOut.println("mean = " + ps.mean());
 StdOut.println("stddev = " + ps.stddev());
 StdOut.println("95% confidence interval = " + ps.confidenceLo() + ", " + ps.confidenceHi());
 }
}


Tags:渗流算法   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
什么是渗流(Percolation)?渗流是物理中用来理解物理现象的一种算法,是很多物理系统的模型。我们假设一个NxN的方形网格,其中的小网格我们叫做位(site),每个site开放(open)的概率...【详细内容】
2019-08-14  Tags: 渗流算法  点击:(173)  评论:(0)  加入收藏
▌简易百科推荐
前言Kafka 中有很多延时操作,比如对于耗时的网络请求(比如 Produce 是等待 ISR 副本复制成功)会被封装成 DelayOperation 进行延迟处理操作,防止阻塞 Kafka请求处理线程。Kafka...【详细内容】
2021-12-27  Java技术那些事    Tags:时间轮   点击:(1)  评论:(0)  加入收藏
博雯 发自 凹非寺量子位 报道 | 公众号 QbitAI在炼丹过程中,为了减少训练所需资源,MLer有时会将大型复杂的大模型“蒸馏”为较小的模型,同时还要保证与压缩前相当的结果。这就...【详细内容】
2021-12-24  量子位    Tags:蒸馏法   点击:(11)  评论:(0)  加入收藏
分稀疏重建和稠密重建两类:稀疏重建:使用RGB相机SLAMOrb-slam,Orb-slam2,orb-slam3:工程地址在: http://webdiis.unizar.es/~raulmur/orbslam/ DSO(Direct Sparse Odometry)因为...【详细内容】
2021-12-23  老师明明可以靠颜值    Tags:算法   点击:(7)  评论:(0)  加入收藏
1. 基本概念希尔排序又叫递减增量排序算法,它是在直接插入排序算法的基础上进行改进而来的,综合来说它的效率肯定是要高于直接插入排序算法的;希尔排序是一种不稳定的排序算法...【详细内容】
2021-12-22  青石野草    Tags:希尔排序   点击:(6)  评论:(0)  加入收藏
ROP是一种技巧,我们对execve函数进行拼凑来进行system /bin/sh。栈迁移的特征是溢出0x10个字符,在本次getshell中,还碰到了如何利用printf函数来进行canary的泄露。ROP+栈迁移...【详细内容】
2021-12-15  星云博创    Tags:栈迁移   点击:(22)  评论:(0)  加入收藏
一、什么是冒泡排序1.1、文字描述冒泡排序是一种简单的排序算法。它重复地走访要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地...【详细内容】
2021-12-15    晓掌柜丶韶华  Tags:排序算法   点击:(16)  评论:(0)  加入收藏
在了解golang的map之前,我们需要了解哈希这个概念。哈希表,又称散列表(Hash table),是根据键(key)而直接访问在内存储存位置的数据结构。也就是说,它通过计算出一个键值的函数,将...【详细内容】
2021-12-07  一棵梧桐木    Tags:哈希表   点击:(14)  评论:(0)  加入收藏
前面文章在谈论分布式唯一ID生成的时候,有提到雪花算法,这一次,我们详细点讲解,只讲它。SnowFlake算法据国家大气研究中心的查尔斯&middot;奈特称,一般的雪花大约由10^19个水分子...【详细内容】
2021-11-17  小心程序猿QAQ    Tags:雪花算法   点击:(24)  评论:(0)  加入收藏
导读:在大数据时代,对复杂数据结构中的各数据项进行有效的排序和查找的能力非常重要,因为很多现代算法都需要用到它。在为数据恰当选择排序和查找策略时,需要根据数据的规模和类型进行判断。尽管不同策略最终得到的结果完...【详细内容】
2021-11-04  华章科技    Tags:排序算法   点击:(40)  评论:(0)  加入收藏
这是我在网上找的资源的一个总结,会先给出一个我看了觉得还行的关于算法的讲解,再配上实现的代码: Original author: Bill_Hoo Original Address: http://blog.sina.com.cn/s/bl...【详细内容】
2021-11-04  有AI野心的电工和码农    Tags: KMP算法   点击:(36)  评论:(0)  加入收藏
相关文章
    无相关信息
最新更新
栏目热门
栏目头条