码迷,mamicode.com
首页 > 其他好文 > 详细

N皇后问题(N queen‘s problem)

时间:2015-03-07 17:18:46      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:

N 皇后问题是一个古老而著名的问题, 是回溯算法(back track)的典型案例。问题描述如下:

N x N 的棋盘上放置N个皇后。 要求同一行中, 同一列中, 以及对角线上(包括正负对角线)只能有一个皇后, 否则就会发生clash的情况而失败。 问解决方案?

解决思路如下:

(1)逐列扫描, 从最左边的列开始, 总共有N个queens。

(2)如果所有的queens 都被安全放置了, 就返回true。

(3)对于给定的列, 尝试所有的行, 此时行是变量, 注意此时此列的左边的所有的列都放置了皇后, 此时我们只需要对当前列的所有行进行扫描, 寻找放置的可行的行,所谓可行就是不会与左边的皇后产生clash, 条件为三个方向, 不同列(当然会满足), 不同行, 不同上斜对角线, 不同下斜对角线。 

(4) 一旦放置好当前的列一个的皇后, 就进入下一列放置。 但是一旦没有产生可行解的时候, 就要回溯(backtrack)到上一列, 重新放置上一列的皇后, 继续重复上述步骤, 直至成功, 否则输出失败。

参考程序如下(4 * 4)参考至geeks for geeks:

#include <iostream>
#include <cstdio>

using namespace std;

const int N = 4;

// a utility function

void printSolution(int board[N][N]) {
    for(int i = 0; i < N; ++i) {
        for(int j = 0; j < N; ++j) {
            cout << board[i][j];
        }
        cout << endl;
    }
}

// a utility function to chreck if a queen can
// be placed on board[row][col], note this function
// is called when 'col' queens already placed in columns
// from 0 to col - 1, so we need to check only left side
// for attacking queens

bool isSafe(int board[N][N], int row, int col) {
    // check row on left side
    for(int i = 0; i < col; ++i) {
        if(board[row][i]) {
            return false;
        }
    }

    // check upper diagonal on left side
    for(int i = row, j = col; i >= 0 && j >= 0; --i, --j) {
        if(board[i][j]) {
            return false;
        }
    }
    // check lower diagonal on left side
    for(int i = row, j = col; i < N && j < col; ++i, --j) {
        if(board[i][j]) {
            return false;
        }
    }
    return true;
}


// a recursive utility function to solve N queen
// problem

bool solveNQUtil(int board[N][N], int col) {
    // base case: if all queens are placed then return true
    if(col >= N) {
        return true;
    }
    // consider this column and try placing this  queen in all rows
    // one by one
    for(int i = 0; i < N; i++) {
        // check if queen can be placed on board
        // board[i][col]
        if(isSafe(board, i, col)) {
            // place this queen on board[i][col]
            board[i][col] = 1;

            // recur to place the rest of the queens
            if(solveNQUtil(board, col + 1) == true) {
                return true;
            }

            // If placing queen on board[i][col] does
            // not leads to a solution, we should remove it
            board[i][col] = 0; // backtrack
        }
    }
    // If queen cannot be placed in any row
    // in this column col, then return false
    return false;
}

bool solveNQ() {
    int board[N][N] = {{0, 0, 0, 0}, {0, 0, 0, 0},
                       {0, 0, 0, 0}, {0, 0, 0, 0}};
    if(solveNQUtil(board, 0) == false) {
        cout << "No solution" << endl;
        return false;
    }
    else {
        printSolution(board);
        return true;
    }
}

// driver program

int main() {
    solveNQ();
    return 0;
}
运行结果如下:

技术分享

参考wiki的http://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/N-Queens, 如下代码产生所有Nqueen的所有的可行解:

#include <iostream>

using namespace std;

const int N = 4;
int position[N]; // 记录解决方案的N个queen的位置

// Check if a position is safe
bool isSafe(int queen_number, int row_position){ // 检查该行是否安全 
	// Check each queen before this one
	for(int i = 0; i < queen_number; i++){ // 当前queen的左边各列的已经安全的queen
		// Get another queen's row_position
		int other_row_pos = position[i]; // 之前的queen存储的位置在position[i]

		// Now check if they're in the same row or diagonals
		if (other_row_pos == row_position || // Same row
			other_row_pos == row_position - (queen_number - i) || // Same diagonal
			other_row_pos == row_position + (queen_number - i))   // Same diagonal
			return false;
	}
	return true;
}


// Recursively generate a tuple like [0 0 0 0], then [0 0 0 1] then etc...
void solve(int k)
{
	if (k == N) // We placed N-1 queens (0 included), problem solved!
	{
		// Solution found!
		cout << "Solution: ";
		for (int i = 0; i < N; i++)
			cout << position[i] << " ";
		cout << endl;
	}
	else
	{
		for (int i = 0; i < N; i++) // Generate ALL combinations
		{
		    // 对于当前的k(放置在k列的皇后), 会尝试玩所有的行
			// Before putting a queen (the k-th queen) into a row, test it for safeness
			if (isSafe(k, i)) // 可以放即执行下面的语句, 将queen k 放置在位置i处
			{
				position[k] = i;
				// Place another queen
				solve(k + 1);
			}
		}
	}
}

int main()
{
	solve(0);

	return 0;
}
运行结果如下:

技术分享

N皇后问题(N queen‘s problem)

标签:

原文地址:http://blog.csdn.net/a130737/article/details/44117053

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!