Algorithms Part1课程第一周的Programming Assignment是Percolation问题,该问题是Union-Find算法的一个应用实例。
作业要求见以下链接:http://coursera.cs.princeton.edu/algs4/assignments/percolation.html,要求用Java实现算法。此外该课程使用了作者提供的API用以简化编程,如基本输入、输出、随机数生成、数据分析等库函数,在上述链接中可直接下载。
模型描述:
Percolation即渗透过程,其模型如下:一个方形“水槽”(system)由N*N个方格(site)组成,每个方格有开启(open)或关闭(blocked)两个状态,相邻(即上下左右)的开启格子能够构成一条同路。如果一个格子处于开启状态,并且与顶端的一行能够通过开启的格子实现连通(connected)通路,我们说这个格子处于充满水(full)的状态;如果一个“水槽”(system)的顶端格子与底部格子通过开启的格子实现了连通,我们称这个“水槽”是可以渗透(percolates)的。如下图所示:
问题描述:
本次作业要求实现上述模型,并计算出“水槽”达到渗透状态时开启格子的数量占所有格子总数的比例(p)。通过蒙特卡洛模拟方法,采用多次模拟采样进行p值的估算。对于不同大小的“水槽”有如下模拟曲线,左图为20*20大小,右图为100*100大小:
Percolation编程分析:
按照作业要求,需要按照以下API创建一个Percolation类作为数据抽象类型:
注意的一点是,在用一维数组模拟二维“水槽”时,我们用i,j坐标进行表示,(i, j)表示的是数组中序号为(i - 1)*N + (j - 1)的元素;此外,由于虚拟点的设置,坐标的对应容易出现混乱,需要首先考虑清楚这个问题。
更重要的一个问题:BackWash即回流/倒灌问题,按照上面的方法设置虚拟点虽然使得检查是否percolate变得方便,但如果水已经渗透到底部,由于虚拟点与底部一排都是连通的,则会通过底部开启的格子向上“灌水”,如下图所示:
解决的方法是:在构造方法中额外定义一个(N*N+1)大小的数组,其不包括底部的虚拟点,其他与(N*N+2)大小的数组一致,在isFull()方法中,我们使用这个(N*N+1)的数组进行检查,也就是说,如果底部的格子确实没有与顶部的虚拟点连通,是不会“灌满”的。下面用图来说明这一过程:
左图中由于底部有虚拟点,右下角的格子出现了倒灌;而右图中由于底部没有虚拟点,不会出现倒灌。注意仅仅在执行percolates()方法时有这一区别。PercolationStats编程分析:
用蒙特卡洛(Monte Carlo)方法进行仿真分析,确定渗透阈值p,具体方法是:
进行以下统计操作。
按照下式计算均值与方差:
假设T值足够大(至少30次),则可以根据下式计算置信区间在95%的的渗透阈值范围:
所有代码见本机。
总结:
如何根据API编译JAVA程序:
1.把API所需要做的内容全都用文字详细写出来,每个步骤该做什么;
2.可以写出伪代码,类似于算法课上所要求的,详尽写出;
3.选好数据结构,简单变成不需要;
4.Coding
经验教训:
0.参数的加入,在Run--Run Configuration--Java application--Arguments--Program Arguments里面加入text的含text的文件名,该文件要存放在项目的子目录下(进入项目的目录放在和bin,src在一起);
1.有bound限制条件的,先把bound写好,再写其他的条件(if(y-1>=0 && openState[x*N+(y-1)] );
2.新建的对象一定要在构造函数里面初始化,且不能在构造函数里面再写一次类名,否则会认为是一个新的对象;
grid = new WeightedQuickUnionUF(N*N+2);
WeightedQuickUnionUF grid;
3.若遇到“重复直到”,“repeat until”这样的语句,要用到while进行判定;
while (!perco.percolates())
4.double/int = int, 出现出现很多隐藏错误,比如如下结果如果不转化就是0. 需要重新令一个变量double x = int,然后再用除法相除。
double transferNsqure = N*N;
int opened++;
x[i] = opened/transferNsqure;