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

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;
}

运行结果如下:

时间: 2024-10-05 00:12:28

N皇后问题(N queen‘s problem)的相关文章

UVA 11538【象棋中的皇后】Chess Queen

1.问题描述 本题主要是讲如何在一个给定的n*m棋盘中放置互相攻击的皇后(处于同一行,或者同一列,或者对角线上的任意两个位置(都不一定两者相邻)),求所能得到互相攻击的皇后的情况. 2.题意分析 本题主要考查加法原理和乘法原理的应用.根据题意可知,我们可以氛围以下方法进行分类求解(加法原理): (1)处于同一行的相互攻击的皇后种数: (2)处于同一列的相互攻击的皇后种数: (3)处于对角线的相互攻击的皇后种数(我们假设n<=m): 本公式很容易证明得出结果. 那么最后的结果我们可以归纳为: 3.

n皇后2种解题思路与代码-Java与C++实现

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 摘要:本文主要讲了n皇后问题的解题思路,并分别用java和c++实现了过程,最后,对于算法改进,使用了位运算. 一.问题抛出与初步解题思路 问题描述:八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行.纵行或斜线上. 转化规则:其实八皇后问题可以推广为更一般的n皇后

回溯(su)算法之N皇后问题

这里回溯算法还要好好研究一下 试探一个位置是否有效,如果有效,试探下一个位置(DFS),如果无效则回退 1.定义一个解空间,存放一个解的空间 2.DFS(暂且认为是DFS) 这里N皇后用的是递归+回溯实现的 1 package com.gxf.backtracking; 2 3 /** 4 * n皇后问题 5 * @author Administrator 6 * 7 */ 8 public class Queen { 9 int num_queen; //皇后个数 10 int solutio

N皇后问题(递归)

//八皇后递归解法 //#include<iostream> //using namespace std; #include<stdio.h> int queen[9] = {-1,-1,-1,-1,-1,-1,-1,-1,-1}; int count = 0;//定义一个全局变量 int n;//(推广到n个皇后问题) bool available(int pointi,int pointj) //判断某个皇后是否与已有皇后冲突 { for(int i = 1; i<poi

八皇后问题(递归方法详解)

八皇后递归详解 核心代码如下: //八皇后递归解法 #include<iostream> using namespace std; int queen[9] = {-1,-1,-1,-1,-1,-1,-1,-1,-1}; int count = 0;//定义一个全局变量 bool available(int pointi,int pointj) //判断某个皇后是否与已有皇后冲突 { for(int i = 1; i<pointi; i++) { if(pointj == queen[i

8皇后问题SQL求解(回溯算法)

问题 八皇后问题是一个古老而著名的问题,是回溯算法的典型例题.该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法 百度来的代码 回溯法用递归实现八皇后解法 declare type t_queen is varray(8) of number; queen t_queen := t_queen(1, 2, 3, 4, 5, 6, 7, 8); l_num number := 0;

学校测试-2015-03-01

记得以前做N皇后问题见到过二进制+位运算优化的方法, 今天的搜索题第三题和第四题都可以用到二进制和位运算. 就只做了这两个题目. 题目三 描述 传递游戏(pass) Description n个人在做传递物品的游戏,编号为1-n. 游戏规则是这样的:开始时物品可以在任意一人手上,他可把物品传递给其他人中的任意一位:下一个人可以传递给未接过物品的任意一人. 即物品只能经过同一个人一次,而且每次传递过程都有一个代价:不同的人传给不同的人的代价值之间没有联系: 求当物品经过所有n个人后,整个过程的最小

C/C++ 笔试题

/////转自http://blog.csdn.net/suxinpingtao51/article/details/8015147#userconsent# 微软亚洲技术中心的面试题!!! 1.进程和线程的差别. 线程是指进程内的一个执行单元,也是进程内的可调度实体.与进程的区别:(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行(3)拥有资源:进程是拥有资源的独立单位,线程不拥有系统资源,但可以访问

51/52. N-Queens -- 待优化

经典的八皇后问题, queen 可以攻击的范围:  水平,垂直,斜向, 放置 queen 让所有的queens 不在对方的攻击范围内,问有多少种方法或者产生相应的棋盘. 分析: 依次产生每一行的结果, 先在某行某个位置放一个结果,如果不能产生解 则back tracking 到上一行,重新放置. 以 n=4 为例,每个位置都得分解 n=4 份, 算法复杂度为 n^n ,是一个很高的结果,因此当 n>12 时,测试用例都会TLE. 需要解决的问题: 1. 如果存储 每个位置, 可以定义一个Node