多執行緒結合經典位運算解n王后問題的優化
在前文的基礎上,結合經典的位運算方法,得出了以下程式碼:
//package com.newflypig.eightqueen; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class EightQueen10 { private static final short K=8; //使用常量來定義,方便之後解N皇后問題 private static short N=0; public static void main(String[] args) throws Exception { for(N=9;N<=17;N++){ long count=0; Date begin =new Date(); /** * 初始化棋盤,使用一維陣列存放棋盤資訊 * chess[n]=X:表示第n行X列有一個皇后 */ List<short[]> chessList=new ArrayList<short[]>(N); for(short i=0;i<N;i++){ short chess[]=new short[N]; chess[0]=(short)(1<<i); chessList.add(chess); } short taskSize =(short)( N/2+(N%2==1?1:0) ); // 建立一個執行緒池 ExecutorService pool = Executors.newFixedThreadPool(taskSize); // 建立多個有返回值的任務 List<Future<Long>> futureList = new ArrayList<Future<Long>>(taskSize); for (int i = 0; i < taskSize; i++) { Callable<Long> c = new EightQueenThread10(chessList.get(i)); // 執行任務並獲取Future物件 Future<Long> f = pool.submit(c); futureList.add(f); } // 關閉執行緒池 pool.shutdown(); for(short i=0; i<(short) (taskSize - (N%2==1?1:0)); i++){ count+=futureList.get(i).get(); } count=count*2; if(N%2==1) count+=futureList.get(N/2).get(); Date end =new Date(); System.out.println("解決 " +N+ "皇后問題,用時:" +String.valueOf(end.getTime()-begin.getTime())+ "毫秒,計算結果:"+count); } } } class EightQueenThread10 implements Callable<Long>{ private short[] chess; private short N; /**sum用來記錄皇后放置成功的不同佈局數*/ public long sum = 0; /**upperlim用來標記所有列都已經放置好了皇后*/ public long upperlim = 1; public EightQueenThread10(short[] chess){ this.chess=chess; this.N=(short) chess.length; upperlim = (upperlim << N) - 1; } @Override public Long call() throws Exception { //System.out.printf("chess[0]=%d\n",chess[0]); return queenPos(chess[0], chess[0]<<1, chess[0]>>1); } private long queenPos(long row, long ld, long rd) { if (row != upperlim) { // row,ld,rd進行“或”運算,求得所有可以放置皇后的列,對應位為0, // 然後再取反後“與”上全1的數,來求得當前所有可以放置皇后的位置,對應列改為1 // 也就是求取當前哪些列可以放置皇后 long pos = upperlim & ~(row | ld | rd); while (pos != 0) // 0 -- 皇后沒有地方可放,回溯 { // 拷貝pos最右邊為1的bit,其餘bit置0 // 也就是取得可以放皇后的最右邊的列 long p = pos & -pos; // 將pos最右邊為1的bit清零 // 也就是為獲取下一次的最右可用列使用做準備, // 程式將來會回溯到這個位置繼續試探 pos -= p; // row + p,將當前列置1,表示記錄這次皇后放置的列。 // (ld + p) << 1,標記當前皇后左邊相鄰的列不允許下一個皇后放置。 // (ld + p) >> 1,標記當前皇后右邊相鄰的列不允許下一個皇后放置。 // 此處的移位操作實際上是記錄對角線上的限制,只是因為問題都化歸 // 到一行網格上來解決,所以表示為列的限制就可以了。顯然,隨著移位 // 在每次選擇列之前進行,原來N×N網格中某個已放置的皇后針對其對角線 // 上產生的限制都被記錄下來了 queenPos(row + p, (ld + p) << 1, (rd + p) >> 1); } } else { // row的所有位都為1,即找到了一個成功的佈局,回溯 sum++; } return sum; } }
優化的效果非常好,幾乎比前文提高了一個數量級。與同演算法的單執行緒相比,也提高了幾倍(我的cpu core i3 4010U 1.7Ghz)
D:\>java EightQueen9 解決 9皇后問題,用時:0毫秒,計算結果:352 解決 10皇后問題,用時:16毫秒,計算結果:724 解決 11皇后問題,用時:15毫秒,計算結果:2680 解決 12皇后問題,用時:47毫秒,計算結果:14200 解決 13皇后問題,用時:281毫秒,計算結果:73712 解決 14皇后問題,用時:1279毫秒,計算結果:365596 解決 15皇后問題,用時:8908毫秒,計算結果:2279184 D:\>javac EightQueen10.java D:\>java EightQueen10 解決 9皇后問題,用時:0毫秒,計算結果:352 解決 10皇后問題,用時:0毫秒,計算結果:724 解決 11皇后問題,用時:16毫秒,計算結果:2680 解決 12皇后問題,用時:0毫秒,計算結果:14200 解決 13皇后問題,用時:46毫秒,計算結果:73712 解決 14皇后問題,用時:219毫秒,計算結果:365596 解決 15皇后問題,用時:1341毫秒,計算結果:2279184 解決 16皇后問題,用時:8237毫秒,計算結果:14772512 解決 17皇后問題,用時:60794毫秒,計算結果:95815104 D:\>java QueenTest3 請輸入皇后數目:15 總共解數為:2279184 程式總共執行時間:5.491s D:\>java QueenTest3 請輸入皇后數目:16 總共解數為:14772512 程式總共執行時間:36.348s
與“世上最快”的單執行緒c程式並駕齊驅。
D:\>timer nq 15 Timer 9.01 : Igor Pavlov : Public domain : 2009-05-31 N Queens program by Jeff Somers. allagash98@yahoo.com or jsomers@alumni.williams.edu Start: Sat Nov 05 07:59:20 2016 End: Sat Nov 05 07:59:22 2016 Calculations took 2 seconds. For board size 15, 2279184 solutions found. Kernel Time = 0.015 = 1% User Time = 1.294 = 84% Process Time = 1.310 = 85% Global Time = 1.526 = 100% D:\>timer nq 16 Timer 9.01 : Igor Pavlov : Public domain : 2009-05-31 N Queens program by Jeff Somers. allagash98@yahoo.com or jsomers@alumni.williams.edu Start: Sat Nov 05 07:59:25 2016 End: Sat Nov 05 07:59:34 2016 Calculations took 9 seconds. For board size 16, 14772512 solutions found. Kernel Time = 0.062 = 0% User Time = 8.611 = 98% Process Time = 8.673 = 99% Global Time = 8.744 = 100% D:\>timer nq 17 Timer 9.01 : Igor Pavlov : Public domain : 2009-05-31 N Queens program by Jeff Somers. allagash98@yahoo.com or jsomers@alumni.williams.edu Start: Sat Nov 05 07:59:50 2016 End: Sat Nov 05 08:00:51 2016 Calculations took 61 seconds. Equals 1 minute and 1 second. For board size 17, 95815104 solutions found. Kernel Time = 0.577 = 0% User Time = 60.403 = 98% Process Time = 60.980 = 99% Global Time = 61.256 = 100%
值得一提的,上述java程式和c程式都利用了同樣的演算法,並都利用翻轉剪枝一半。
相關文章
- 多執行緒解n王后問題的優化執行緒優化
- 利用C++多執行緒優化n王后問題C++執行緒優化
- 多執行緒經典面試題執行緒面試題
- 總結:iOS中多執行緒的經典崩潰iOS執行緒
- 多執行緒問題解釋執行緒
- java多執行緒總結六:經典生產者消費者問題實現Java執行緒
- 多執行緒問題執行緒
- 多執行緒下的程式同步(執行緒同步問題總結篇)執行緒
- java多執行緒執行問題Java執行緒
- 多執行緒鎖的問題執行緒
- Java面試經典題:執行緒池專題Java面試執行緒
- 【java 多執行緒】多執行緒併發同步問題及解決方法Java執行緒
- 位運算解決多標籤問題【原創】
- 改進的sql計算n王后SQL
- 40 個 Java 多執行緒問題總結Java執行緒
- 40個Java多執行緒問題總結Java執行緒
- 多執行緒的安全問題及解決方案執行緒
- java 執行緒淺解03[執行緒同步以及經典死鎖]Java執行緒
- Java多執行緒面試高配問題---多執行緒(3)🧵Java執行緒面試
- 使用執行緒池優化多執行緒程式設計執行緒優化程式設計
- 多執行緒併發安全問題詳解執行緒
- 多執行緒程式設計,處理多執行緒的併發問題(執行緒池)執行緒程式設計
- 多執行緒-執行緒安全問題的產生原因分析以及同步程式碼塊的方式解決執行緒安全問題執行緒
- 【多執行緒】常見問題簡單總結執行緒
- 多執行緒相關問題執行緒
- Hibernate 多執行緒問題!執行緒
- 面試官常問的位運算問題總結面試
- iOS多執行緒全套:執行緒生命週期,多執行緒的四種解決方案,執行緒安全問題,GCD的使用,NSOperation的使用iOS執行緒GC
- 多執行緒-多執行緒常見的面試題執行緒面試題
- Java多執行緒中執行緒安全與鎖問題Java執行緒
- WebMagic多執行緒導致註解失效問題Web執行緒
- 多執行緒引起的效能問題分析執行緒
- seam中使用多執行緒的問題執行緒
- 一個多執行緒的PushbackInputStream問題執行緒
- java多執行緒問題 多核cpu遇上java多執行緒,求解釋Java執行緒
- 面試系列-40個Java多執行緒問題總結面試Java執行緒
- 【面經】多執行緒常見面試題執行緒面試題
- Java中多執行緒的概述、實現方式、執行緒控制、生命週期、多執行緒程式練習、安全問題的解決...Java執行緒