求解系統的滲透閾值——基於union-find演算法
阿新 • • 發佈:2018-11-05
問題描述:http://coursera.cs.princeton.edu/algs4/assignments/percolation.html
Percolation的求解基於Union-Find演算法,這裡用了Quick Find和Weighted Quick Union演算法,並對兩種演算法進行了比較。
首先建立滲透模型類:
/ ** * @Author DXH924 * Xidian University */ /*滲透模型*/ import java.lang.Math; public class Percolation{ static int[][] a;//虛擬化網格 static int[] id;//每個網格對應的id,相同id的網格視為連通 public int size;//網格數量 public int cnt=0;//“開啟”的網格數 public int top, bottom;//增加兩個虛擬化的網格(頂部和底部) public Percolation(int N){ a=new int[N][N]; size=N*N+2; top=size-2; bottom=size-1; id=new int[size]; for (int i=0; i<size; i++) id[i]=i; //將系統頂部與底部分別抽象為一個網格 for (int i=0; i<N; i++) id[i]=id[top]; for (int i=size-2-N; i<size-2; i++) id[i]=id[bottom]; }//滲透系統初始化 public void open(int i, int j){ a[i][j]=1; cnt++; }//開啟網格(i, j) public boolean isOpen(int i, int j){ return a[i][j]==1; }//網格是否開啟 public boolean isFull(int i, int j){ return a[i][j]==0; }//網格是否阻塞 public void union(int p, int q){ int pID=find(p), qID=find(q); if (pID==qID) return; for (int i=0; i<size; i++) if (id[i]==pID) id[i]=qID; }//基於QF的連通方式 public int find(int p){ return id[p]; }//找到連通分量的id public boolean connected(int i, int j){ return find(i)==find(j); }//判斷i與j是否連通 public boolean percolates(){ if (connected(top, bottom)) return true; return false; }//判斷系統是否滲透 public void set(int N){ int i=(int)(Math.random()*N); int j=(int)(Math.random()*N); if (isOpen(i, j)) return; open(i, j);//設定open格點 int p, q=0;//p為(i,j)的格子,q為p相鄰的格子 p=i*N+j; if (i-1>=0){ q=p-N; if (a[i-1][j]==1) union(p, q); } if (j+1<N){ q=p+1; if (a[i][j+1]==1) union(p, q); } if (i+1<N){ q=p+N; if (a[i+1][j]==1) union(p, q); } if (j-1>=0){ q=p-1; if (a[i][j-1]==1) union(p, q); } }//連通與(i, j)相鄰的網格 public double test(int N){ while (!percolates()){ int i=(int)(Math.random()*N); int j=(int)(Math.random()*N); set(N); } double mean=cnt*1.0/(size-2); return mean; }//計算滲透閾值 }//based on Quick Find /*QuickFind類*/ public class QF extends Percolation{ public QF(int N){ super(N); } } /*WeightedQuickUnion類*/ public class WQU extends Percolation{ public int[] sz;//連通分量的大小 public WQU(int N){ super(N); sz=new int[size]; for (int i=0; i<size; i++) sz[i]=1; } public void union(int p, int q){ int i=find(p), j=find(q); if (i==j) return; if (sz[i]<sz[j]){ id[i]=j; sz[j]+=sz[i]; } else{ id[j]=i; sz[i]+=sz[j]; } }//基於Weighted Quick Union, 根據權重連通分量 public int find(int p){ while (id[p]!=p) p=id[p]; return p; }//尋找與p連通的分量id }//based on Weight Quick Union
計算及測試類:
/*計算及測試類*/ public class PercolationStats { int N, T;//N為系統規模,T為測試資料組數 double sample[];//每組測試資料樣本值 double mean=0, stddev, lo, hi;//滲透閾值,標準差以及置信區間 double start, end, runtime;//執行時間 public PercolationStats(int N, int T, String arg){ this.N=N; this.T=T; sample=new double[T]; start=System.currentTimeMillis(); if (arg.equals("Quick Find")) for (int i=0; i<T; i++){ Percolation qf=new QF(N); sample[i]=qf.test(N); } if (arg.equals("Weighted Quick Union")) for (int i=0; i<T; i++){ Percolation wqu=new WQU(N); sample[i]=wqu.test(N); } end=System.currentTimeMillis(); runtime=end-start; } // sample mean of percolation threshold public double mean(){ double sum=0; for (int i=0; i<T; i++) sum+=sample[i]; mean=sum/T; return mean; } // sample standard deviation of percolation threshold public double stddev(){ double sigma_2, sum=0; for (int i=0; i<T; i++) sum+=(sample[i]-mean)*(sample[i]-mean); sigma_2=sum/(T-1); stddev=Math.sqrt(sigma_2); return stddev; } //returns lower bound of the 95% confidence interval public double confidenceLo(){ lo=mean-1.96*stddev/Math.sqrt(T); return lo; } //returns upper bound of the 95% confidence interval public double confidenceHi(){ hi=mean+1.96*stddev/Math.sqrt(T); return hi; } } import java.util.*; public class PercolationTest { public static void main(String[] args){ int N, T; String arg1="Quick Find"; String arg2="Weighted Quick Union"; System.out.println("enter N and T:"); Scanner input=new Scanner(System.in); N=input.nextInt(); T=input.nextInt(); for (int i=0; i<5; i++, N*=2){ PercolationStats qf=new PercolationStats(N, T, arg1); PercolationStats wqu=new PercolationStats(N, T, arg2); show(qf, arg1); show(wqu, arg2); System.out.println("When N = "+N+" ,"); System.out.println(arg2+" is "+qf.runtime/wqu.runtime+" times faster than "+arg1); System.out.println(); } } public static void show(PercolationStats t, String arg){ System.out.println(arg); System.out.println("N = "+t.N+", T = "+t.T); System.out.println("mean = "+t.mean()); System.out.println("stddev = "+t.stddev()); System.out.println("confidenceLow = "+t.confidenceLo()); System.out.println("confidenceHigh = "+t.confidenceHi()); System.out.println("running time = "+t.runtime+"ms\n"); } }
測試樣例:
enter N and T: 20 50 Quick Find N = 20, T = 50 mean = 0.59345 stddev = 0.05346153013225148 confidenceLow = 0.5786312198882635 confidenceHigh = 0.6082687801117366 running time = 14.0ms Weighted Quick Union N = 20, T = 50 mean = 0.59695 stddev = 0.04694843567409778 confidenceLow = 0.583936557565348 confidenceHigh = 0.609963442434652 running time = 8.0ms When N = 20 , Weighted Quick Union is 1.75 times faster than Quick Find Quick Find N = 40, T = 50 mean = 0.6013999999999999 stddev = 0.02381052974065492 confidenceLow = 0.5948000578790416 confidenceHigh = 0.6079999421209583 running time = 49.0ms Weighted Quick Union N = 40, T = 50 mean = 0.59295 stddev = 0.031969283328385896 confidenceLow = 0.5840885667637791 confidenceHigh = 0.6018114332362209 running time = 34.0ms When N = 40 , Weighted Quick Union is 1.4411764705882353 times faster than Quick Find Quick Find N = 80, T = 50 mean = 0.5915874999999999 stddev = 0.01903813368268796 confidenceLow = 0.5863103985761594 confidenceHigh = 0.5968646014238405 running time = 453.0ms Weighted Quick Union N = 80, T = 50 mean = 0.59128125 stddev = 0.021882378493217065 confidenceLow = 0.5852157641373505 confidenceHigh = 0.5973467358626494 running time = 48.0ms When N = 80 , Weighted Quick Union is 9.4375 times faster than Quick Find Quick Find N = 160, T = 50 mean = 0.5930671875 stddev = 0.010708300388289247 confidenceLow = 0.5900989980667396 confidenceHigh = 0.5960353769332604 running time = 6405.0ms Weighted Quick Union N = 160, T = 50 mean = 0.5936234375 stddev = 0.012259872074749474 confidenceLow = 0.5902251743372303 confidenceHigh = 0.5970217006627697 running time = 198.0ms When N = 160 , Weighted Quick Union is 32.34848484848485 times faster than Quick Find Quick Find N = 320, T = 50 mean = 0.5923541015624999 stddev = 0.006205852182211583 confidenceLow = 0.5906339270993554 confidenceHigh = 0.5940742760256444 running time = 99309.0ms Weighted Quick Union N = 320, T = 50 mean = 0.5916140625000001 stddev = 0.0081841638093851 confidenceLow = 0.5893455280306407 confidenceHigh = 0.5938825969693596 running time = 807.0ms When N = 320 , Weighted Quick Union is 123.05947955390334 times faster than Quick Find
演算法 | 建構函式 | union() | find() |
---|---|---|---|
quick-find | N | N | 1 |
quick-union | N | 樹的高度 | 樹的高度 |
加權quick-union | N | lgN | lgN |
路徑壓縮加權quick-union | N | →1 | →1 |
理想情況 | N | 1 | 1 |
BY DXH924
2018.10.23