报了coursera的algorithms, part I课程,第一周的编程作业是Percolation。做出来并不难,但就是有一个backwash的情况。刚开始想用两个UF实例做,但是checklists里明显说了可以用一个UF实例完成,百思不得其解。搜索discussion forum发现http://tech-wonderland.net/blog/avoid-backwash-in-percolation.html这里讲了如何用一个UF解决backwash的思路,循着思路终于写出了代码。
1 public class Percolation { 2 // 0: block 1: open 2: connected to top 4: connected to bottom 3 private byte[] lattice; 4 private WeightedQuickUnionUF uf; 5 private int size; 6 private boolean percolate; 7 8 public Percolation(int N) { 9 if (N <= 0) throw new java.lang.IllegalArgumentException(); 10 size = N; 11 uf = new WeightedQuickUnionUF(N*N); 12 lattice = new byte[N*N]; 13 percolate = false; 14 } 15 16 public void open(int i, int j) { 17 validate(i, j); 18 int position = xyTo1D(i, j); 19 if ((lattice[position] & 1) == 0) { 20 int uPosition = xyTo1D(i-1, j); 21 int dPosition = xyTo1D(i+1, j); 22 int lPosition = xyTo1D(i, j-1); 23 int rPosition = xyTo1D(i, j+1); 24 if (dPosition >= size*size) 25 dPosition = -1; 26 if (j == 1) 27 lPosition = -1; 28 if (j == size) 29 rPosition = -1; 30 int[] positions = {uPosition, dPosition, lPosition, rPosition}; 31 int[] stats = new int[4]; 32 for (int idx = 0; idx < 4; idx++) { 33 int p = positions[idx]; 34 if ((p >= 0) && ((lattice[p] & 1) == 1)) { 35 stats[idx] = lattice[uf.find(p)]; 36 uf.union(position, p); 37 } 38 } 39 int root = uf.find(position); 40 for (int idx = 0; idx < 4; idx++) { 41 lattice[root] |= stats[idx]; 42 } 43 lattice[position] |= 1; 44 if (i == 1) lattice[root] |= 2; 45 if (i == size) lattice[root] |= 4; 46 if ((lattice[root] & 7) == 7) percolate = true; 47 } 48 } 49 50 public boolean isOpen(int i, int j) { 51 validate(i, j); 52 return (lattice[xyTo1D(i, j)] & 1) == 1; 53 } 54 55 public boolean isFull(int i, int j) { 56 validate(i, j); 57 return (lattice[uf.find(xyTo1D(i, j))] & 3) == 3; 58 } 59 60 public boolean percolates() { 61 return percolate; 62 } 63 64 private void validate(int i, int j) { 65 if (i < 1 || i > size || j < 1 || j > size) 66 throw new java.lang.IndexOutOfBoundsException(); 67 } 68 69 private int xyTo1D(int i, int j) { 70 return (i - 1) * size + j - 1; 71 } 72 }
代码可能比较丑,好久没写过Java代码,都忘记了,数组都不知道怎么初始化。这个方法与利用虚拟格子的方式不同,它将lattice是否percolate的信息存储在了每个联通分量的根节点中。也许事先什么都不知道直接来实现percolate更容易想到这个方法,但如果一直记着虚拟格子,反而更难拓宽思路。还有代码中lattice用byte类型,这样可以使代码的内存使用量大概为9N^2bytes,如果使用int的话就得12N^2,这样就拿不到bonus的分数了。当然其实每个格子4bit就可以存储状态了,但没有那么严格的要求,用byte也就可以了。
时间: 2024-10-09 21:39:43