1. 程式人生 > >N-Queens I/II

N-Queens I/II

需求I:

n皇后問題,有一個n*n的棋盤,有n個皇后,要保證每個皇后不能在同一行、同一列、同一對角線,這樣才不會出現衝突,求解n皇后共有多少种放置方式。

分析:

1、建立n*n的char型二維陣列,初始化為'.',表示沒有放置皇后。

2、因為皇后不能在同一行,所以將皇后i放到行i,逐行確定每個皇后的位置。假設,現在要確定皇后num(num的範圍是0~n-1)的位置,如果num==n,那麼說明已經找到了一個可行解,將該陣列轉化成字串集合,新增到結果集合中即可。如果num<n,那麼該皇后可以放置的位置有[0, n-1],假設放到位置i處,判斷[num][i]處放置皇后是否合法,如果合法,將[num][i]置為'Q',然後尋找皇后num+1的位置,然後將[num][i]置為'.',繼續判斷皇后num是否可以放到其它位置。如果不合法,那麼繼續判斷皇后是否可以放到其它位置。

3、判斷皇后的位置是否合法。因為每個皇后都位於不同行,所以只需要判斷皇后的位置是否位於同一列或者同一對角線即可。對於皇后num,只需要判斷比num小的皇后的位置即可。假如兩個皇后的位置分別是[i1][j1]和[i2][j2],那麼只需要保證j1 != j2(不在同一列),並且|i1-i2| != |j1-j2|(不在同一對角線)即可。

4、將二維字元陣列轉成字串集合。建立字串集合,將二維陣列的每一行轉成字串,新增到集合中即可。

程式碼:

class Solution {
    public List<List<String>> solveNQueens(int n) {
        List<List<String>> res = new LinkedList<List<String>>();
        
        //建立n*n陣列,初始化為'.'
        char[][] board = new char[n][n];
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                board[i][j] = '.';
        
        //求皇后0的位置
        dfs(0, board, res);
        return res;
    }
    
    //確定皇后num的位置
    public void dfs(int num, char[][] board, List<List<String>> res){
        //如果num==board.length,說明已經找到了可行解,將其新增到res中
        if(num == board.length){
            res.add(arraytolist(board));
            return;
        }
        
        //確定皇后num放置的位置
        for(int i = 0; i < board.length; i++){
            if(valid(num, i, board)){
                board[num][i] = 'Q';
                dfs(num+1, board, res);
                board[num][i] = '.';
            }
        }
    }
    
    //判斷皇后num的位置是否合法
    public boolean valid(int num, int col, char[][] board){
        for(int i = 0; i < num; i++){
            for(int j = 0; j < board.length; j++){
                if(board[i][j] == 'Q'){
                    if(j == col || Math.abs(i-num) == Math.abs(j-col))
                        return false;
                }
            }
        }
        
        return true;
    }
    
    //將二維字元陣列轉化成字串集合
    public List<String> arraytolist(char[][] board){
        List<String> res = new LinkedList<String>();
        
        for(int i = 0; i < board.length; i++)
            res.add(new String(board[i]));
        
        return res;
    }
}

需求II:

n皇后問題,求總的排列個數。

分析:

相對於上述問題,不需要將所有可行解儲存起來,只需要記錄個數即可,思路相同,更簡單一些。

程式碼:

class Solution {
    //相對於NQueens I來說,不需要建立集合來儲存結果,只需要一個變數,來遞增數量即可
    int res = 0;
    public int totalNQueens(int n) {
        //建立n*n二維字元陣列,初始化為'.'
        char[][] board = new char[n][n];
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                board[i][j] = '.';
        
        dfs(0, board);//確定皇后0的位置
        return res;
    }
    
    public void dfs(int num, char[][] board){
        if(num == board.length)
        {
            res++;//已經找到了一個可行解
            return;
        }
        
        for(int i = 0; i < board.length; i++){
            if(valid(num, i, board)){
                board[num][i] = 'Q';
                dfs(num+1, board);
                board[num][i] = '.';
            }
        }
    }
    
    public boolean valid(int num, int col, char[][] board){
        for(int i = 0; i < num; i++){
            for(int j = 0; j < board.length; j++){
                if(board[i][j] == 'Q'){
                    if(j == col || Math.abs(i-num) == Math.abs(j-col))
                        return false;
                }
            }
        }
        
        return true;
    }
}