多執行緒解n王后問題的優化

lt發表於2016-11-04

在網上看到這個程式,作者給出的時間和我實際執行有很大差距。 他的

15皇后,用時:4903毫秒,計算結果:2279184

16皇后,用時:33265毫秒,計算結果:14772512

17皇后,用時:267460毫秒,計算結果:95815104

我的

D:\>javac EightQueen7.java

D:\>java EightQueen7
解決 9皇后問題,用時:94毫秒,計算結果:352
解決 10皇后問題,用時:7毫秒,計算結果:724
解決 11皇后問題,用時:47毫秒,計算結果:2680
解決 12皇后問題,用時:131毫秒,計算結果:14200
解決 13皇后問題,用時:666毫秒,計算結果:73712
解決 14皇后問題,用時:2707毫秒,計算結果:365596
解決 15皇后問題,用時:23059毫秒,計算結果:2279184
解決 16皇后問題,用時:142386毫秒,計算結果:14772512
解決 17皇后問題,用時:1226259毫秒,計算結果:95815104

約為他的5倍。我的機器CPU是:pentium G3450 3.4Ghz

把他的程式改成二進位制位運算,速度提高了1倍。

//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 EightQueen8 {
    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]=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 EightQueenThread(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 EightQueenThread implements Callable<Long>{
    private short[] chess;
    private short N;
    static int []w =new int[300];
    static int []w1=new int[300];
    static int []w2=new int[300];     

    public EightQueenThread(short[] chess){
        this.chess=chess;
        this.N=(short) chess.length;
            //init w w1 w2
       for(int n=1;n<=N*N;n++)
       {
           int r=(n-1)/N+1;
           int c=(n-1)%N+1;
           //System.out.printf("%d,%d,%d,%d,%d,%d\n",n,r,c,1<<c,1<<(r+c-2),1<<(r-c+N-1));
           w[n]=1<<c;
           w1[n]=1<<(r+c-2);
           w2[n]=1<<(r-c+N-1);
           }     


    }


    @Override
    public Long call() throws Exception {
        //System.out.printf("chess[0]=%d\n",chess[0]);
        return putQueenAtRow(chess, (short)1,w[chess[0]+1],w1[chess[0]+1],w2[chess[0]+1]) ;
    }


    private Long putQueenAtRow(short[] chess, short row,int sw,int sw1,int sw2) {
        if(row==N){
            //System.out.printf("find one result:%d %d %d %d\n",chess[0],chess[1],chess[2],chess[3]);
            return (long) 1;
        }

        short[] chessTemp=chess.clone();
        long sum=0;
        /**
         * 向這一行的每一個位置嘗試排放皇后
         * 然後檢測狀態,如果安全則繼續執行遞迴函式擺放下一行皇后
         */
        for(short i=0;i<N;i++){
            //擺放這一行的皇后
            chessTemp[row]=i;

            //if( isSafety( chessTemp,row,i) ){
            int n=(row)*N+i+1;
            if(( w[n]& sw) ==0 &&(w1[n]& sw1)==0 && (w2[n]& sw2)==0) {
                //System.out.printf("n=%d,%d,%d,%d,%d,%d,%d\n",n,sw, sw1, sw2,w[n], w1[n],w2[n]);

                sum+=putQueenAtRow(chessTemp,(short) (row+1),sw+w[n],sw1+w1[n],sw2+w2[n]);
            }
        }

        return sum;
    }

    private static boolean isSafety(short[] chess,short row,short col) {
        //判斷中上、左上、右上是否安全
        short step=1;
        for(short i=(short) (row-1);i>=0;i--){
            if(chess[i]==col)   //中上
                return false;
            if(chess[i]==col-step)  //左上
                return false;
            if(chess[i]==col+step)  //右上
                return false;

            step++;
        }

        return true;
    }
}

D:\>javac EightQueen8.java

D:\>java EightQueen8
解決 9皇后問題,用時:16毫秒,計算結果:352
解決 10皇后問題,用時:0毫秒,計算結果:724
解決 11皇后問題,用時:48毫秒,計算結果:2680
解決 12皇后問題,用時:112毫秒,計算結果:14200
解決 13皇后問題,用時:538毫秒,計算結果:73712
解決 14皇后問題,用時:2246毫秒,計算結果:365596
解決 15皇后問題,用時:14686毫秒,計算結果:2279184
解決 16皇后問題,用時:85156毫秒,計算結果:14772512
解決 17皇后問題,用時:723597毫秒,計算結果:95815104

在一臺xeon E5420 2.5Ghz*2的機器上的結果

C:\>javac EightQueen7.java

C:\>java EightQueen7
解決 9皇后問題,用時:78毫秒,計算結果:352
解決 10皇后問題,用時:31毫秒,計算結果:724
解決 11皇后問題,用時:0毫秒,計算結果:2680
解決 12皇后問題,用時:47毫秒,計算結果:14200
解決 13皇后問題,用時:203毫秒,計算結果:73712
解決 14皇后問題,用時:952毫秒,計算結果:365596
解決 15皇后問題,用時:5709毫秒,計算結果:2279184
解決 16皇后問題,用時:39531毫秒,計算結果:14772512
解決 17皇后問題,用時:330454毫秒,計算結果:95815104

C:\>javac EightQueen8.java

C:\>java EightQueen8
解決 9皇后問題,用時:15毫秒,計算結果:352
解決 10皇后問題,用時:32毫秒,計算結果:724
解決 11皇后問題,用時:0毫秒,計算結果:2680
解決 12皇后問題,用時:31毫秒,計算結果:14200
解決 13皇后問題,用時:109毫秒,計算結果:73712
解決 14皇后問題,用時:577毫秒,計算結果:365596
解決 15皇后問題,用時:2699毫秒,計算結果:2279184
解決 16皇后問題,用時:17129毫秒,計算結果:14772512
解決 17皇后問題,用時:140915毫秒,計算結果:95815104

相關文章