【算法导论】八皇后问题的算法实现(C、MATLAB、Python版)

        八皇后问题是一道经典的回溯问题。问题描述如下:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8*8个方格),使它们谁也不能被吃掉?

        看到这个问题,最容易想到的就是遍历穷举法,不过仔细一想,思路虽然非常清晰,但是需要遍历次数太多,时间复杂度很高。那么,我们应该怎么办呢?下面给出算法思路:

        算法思想:首先尝试在第一行放置第一个皇后,然后在第二行放置第二个使之与前面的皇后不构成威胁,依此类推。如果发现不能放置下一个皇后,就回溯到上一步,试着将皇后放在其他的位置。最后,或者尝试完所有的可能或者找到解决方案。

        这种算法思想与中国的一句古话“不撞南墙不回头”类似:一路向前走,直到走到死胡同,然后往回走,回到上一个岔路口,重新选择一个方向,继续向前走,直到到达目的地。

        下面给出了该算法的具体实现,用C、MATLAB、PYTHON分别进行了实现,由于程序给出了比较详细的注释,因此就不对具体程序解释说明了。

C语言实现:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define N 8//棋盘大小

int matrix[N][N];//存储皇后的位置,其实也可以用一维数组表示

void PrintQueen();//打印棋盘
void PlaceQueen(int row);//放置皇后
int Conflict(int row,int col);//检查当前皇后是否与之前的冲突

int main()
{
    PlaceQueen(0);
    return 0;
}

void PrintQueen()
{
    static int solutionNum=0;//看总共有多少种情况
    solutionNum+=1;
    int row,col;
    printf("第%d种方法:\n",solutionNum);
    for(row=0;row<N;row+=1)
    {
        for(col=0;col<N;col+=1)
        {
            if(matrix[row][col])
            {
                printf("* ");
            }
            else
            {
                printf("- ");
            }
        }
        printf("\n");
    }
    printf("\n");
}

int Conflict(int row,int col)
{
	for (int m = 0; m <row ; m++)
	{
        for (int n = 0; n <N; n++)
		{
            if (matrix[m][n] == 1) //  每一行只有一个皇后
			{
                if ( n == col || abs(row - m) == abs(col - n) )   // 检查是否与之前的皇后冲突
                    return false;
            }
        }
    }
    return true;
}

void PlaceQueen(int row)
{
	if(row>=N)//已经放置了N个皇后
	{
		PrintQueen();
	}
	else
	{
		for(int col=0;col<N;col++)
		{
			matrix[row][col]=1;
			if(row==0||Conflict(row,col))
					PlaceQueen(row+1);//递归调用
			matrix[row][col]=0;
		}

	}

}

MATLAB实现

脚本文件Queen.m

 clear all
clc

global solutionNum;
solutionNum=0;%全局变量记录方法数
N=8;%皇后个数
matrix=zeros(N);%存储皇后位置信息

PlaceQueen(1,matrix,N)%调用放置方法

函数文件PlaceQueen.m

function PlaceQueen(row,matrix,N)%回溯法放置皇后

    if row>N
        PrintQueen(N,matrix);%打印棋盘
    else
        for col=1:N
            matrix(row,col)=1;
            if row==1||Conflict(row,col,N,matrix)%检测是否冲突
                PlaceQueen(row+1,matrix,N);
            end
            matrix(row,col)=0;
        end
    end

    %子函数:检测冲突
    function result=Conflict(row,col,N,matrix)%检测是否冲突

    result=1;
    for i=1:row-1
        for j=1:N
            if matrix(i,j)==1
                if ((j==col)||(abs(row-i)==abs(col-j)))%是否产生冲突:在同一直线,斜线上
                    result=0;
                    break;
                end
            end
        end
        if result==0
            break;
        end
    end

    %子函数:打印棋盘信息
function PrintQueen(N,matrix)

    global solutionNum; %定义全局变量,来累积方法数
    solutionNum=solutionNum+1;

    disp(['第',num2str(solutionNum),'种方法:'])

disp(matrix)

PYTHON实现:

def conflict(state,nextX):#冲突检测函数
    nextY=len(state)
    for i in range(nextY):
        if abs(state[i]-nextX) in (0,nextY-i):#检测是否在同一直线、斜线
            return True
    return False

def queens(num=8,state=()): #放置皇后,采用元组state来存储皇后的位置
    for pos in range(num):
        if not conflict(state,pos):
            if len(state)==num-1:
                yield (pos)
            else:
                for result in queens(num,state+(pos,)):
                    yield (pos,)+result

for solution in queens(8):
    print (solution)

print('总共的方法数为:',len(list(queens(8))))

运行结果分别如下:


1、C语言的运行结果:

2、MATLAB语言的运行结果:

3、PYTHON语言的运行结果:

 

扩展:

上面的程序中,改变N的值就可以解决N皇后的问题了,但还可以用分治法来解决N皇后的问题,具体参见文献《N皇后问题解的构造和等价性分析》。下面的Matlab程序给出了一个简单的算法过程:

4皇后的一种放置方式:

     0     0     1     0

     1     0     0     0

     0     0     0     1

     0     1     0     0

根据4皇后的放置方式可以推导出16皇后的一种放置方式:

     0     0     0     0     0     0     0     0     0     0     1     0     0     0     0     0

     0     0     0     0     0     0     0     0     1     0     0     0     0     0     0     0

     0     0     0     0     0     0     0     0     0     0     0     1     0     0     0     0

     0     0     0     0     0     0     0     0     0     1     0     0     0     0     0     0

     0     0     1     0     0     0     0     0     0     0     0     0     0     0     0     0

     1     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0

     0     0     0     1     0     0     0     0     0     0     0     0     0     0     0     0

     0     1     0     0     0     0     0     0     0     0     0     0     0     0     0     0

     0     0     0     0     0     0     0     0     0     0     0     0     0     0     1     0

     0     0     0     0     0     0     0     0     0     0     0     0     1     0     0     0

     0     0     0     0     0     0     0     0     0     0     0     0     0     0     0     1

     0     0     0     0     0     0     0     0     0     0     0     0     0     1     0     0

     0     0     0     0     0     0     1     0     0     0     0     0     0     0     0     0

     0     0     0     0     1     0     0     0     0     0     0     0     0     0     0     0

     0     0     0     0     0     0     0     1     0     0     0     0     0     0     0     0

     0     0     0     0     0     1     0     0     0     0     0     0     0     0     0     0

依次类推,可以得到4的幂次皇后的一种放置方式,不过值得注意的是:2、3、8、9、14、15、26、27、38、39这10个N值不能采用这种分治法。

由4皇后直接推出16皇后的Matlab实现如下:

clear all
clc

a4=[  0     0     1     0
     1     0     0     0
     0     0     0     1
     0     1     0     0]
 [asize bsize]=size(a4);

 a16=zeros(asize^2,bsize^2);
 [rowIndex,colIndex]=find(a4);

 for i=1:length(rowIndex)
     a16((1+asize*(rowIndex(i)-1)):asize*rowIndex(i),(1+asize*(colIndex(i)-1)):asize*colIndex(i))=a4;
 end
 a16

运行结果如下:

原文:http://blog.csdn.net/tengweitw/article/details/44648249
作者:nineheadedbird

时间: 2024-09-16 02:14:46

【算法导论】八皇后问题的算法实现(C、MATLAB、Python版)的相关文章

算法导论-看到好几个Bellman-Ford算法都是这样写的,我有个疑问

问题描述 看到好几个Bellman-Ford算法都是这样写的,我有个疑问 for(int i = 1; i <= nodenum - 1; ++i) for(int j = 1; j <= edgenum; ++j) if(dis[edge[j].v] > dis[edge[j].u] + edge[j].cost) //松弛(顺序不能错) { dis[edge[j].v] = dis[edge[j].u] + edge[j].cost; pre[edge[j].v] = edge[j]

算法导论-一个关于二分法的算法问题

问题描述 一个关于二分法的算法问题 一个建筑有n层,有k个学生,我们想用学生往下跳的方式寻找所谓的"致命楼层e",也就说挑一个学生从这一层(e)向下跳会死人.有个函数jump(i)可以判断第i层是否致命,返回true是致命,false是不致命.假设jump(1)是false,saut(n)是true.一个学生可以重复利用.目的是使跳的次数最小化. (1)如果 k = 1,怎样寻找一个算法?跳的次数的最坏情况是? (2)如果k ≥logn(以2为底),设计一个算法,使得最坏情况是o(lo

【算法导论】排序 (二):堆排序

四.(1)堆排序 第一次听堆排序是在107lab听忠哥讲的,但是没讲怎么实现.那时刚看了数据结 构的二叉树,还以为要通过指针建立二叉树的方式来实现,觉得挺难的. 其实堆排序实现没有想象中 的那么难. "堆"这个词最初是在堆排序中提出来的,但后来就逐渐指"废料收集储存区",就像程 序设计语言Lisp和Java中所提供的设施那样.我们这里的堆数据结构不是废料收集存储区. 堆排序的 运行时间与归并排序一样为O(n lg n),  但是一种原地(in place)排序. (

【算法导论】排序(一)

虽然久闻大名,但第一次接触算法导论,是看了网易公开课MIT的<算法导论>课,记得 第一集就讲到了 插入排序和归并排序. 几个星期前也买了算法导论这本书,准备慢慢啃~ 这星期主要在看前两 部分,除了对于讲渐进时间.递归式分析这些东西感到云里雾里的,其它的都就 感觉越看越有觉得入 迷,果然不愧是一本经典之作 好吧,开始.本文主要是用C++把书中的算法实现,以及一些笔记. 一.插入排序. 插入算法的设计使用的是增量(incremental)方法:在排好子数组A[1..j- 1]后,将 元素A[ j]

JavaScript解八皇后问题的方法总结_javascript技巧

关于八皇后问题的 JavaScript 解法,总觉得是需要学习一下算法的,哪天要用到的时候发现真不会就尴尬了 背景八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行.纵行或斜线上 八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为 n×n ,而皇后个数也变成n .当且仅当n = 1或n ≥ 4时问题有解 盲目的枚举算法通过N重循环,枚举满足约束条件的解(八重

也来说一下八皇后问题

       (本文的所有代码均是基于此文:http://blog.csdn.net/mbh_1991/article/details/23869459,感谢博主的贡献!)          最近看了一篇文章(见上面给出的链接),里面讲到了回溯算法和八皇后问题.仔细阅读全文之后,发现作者所写与实际开发工作还是有一定的差别,因此特发此文,表达一下个人的看法,请各位批评指正.        什么是回溯算法?举个例子来说,当你走到一个有很多岔路的路口,不知道哪条路是通的,于是,你随便选择了一条,当走到

常用算法:C#八皇后问题

八皇后问题是一个古老而著名的问题,是回溯算法的典型应用.八皇后问题就是棋盘上的8个皇后不能在同一行.一列或一条斜线上,在8!=40320种排列中共有92种解决方案.代码如下: using System; using System.Collections.Generic; using System.Text;namespace ExQueen { class Queen { public void QueenArithmetic(int size){ int[] Queen = new int[s

八皇后算法问题

问题描述 问题是下面算法,为什么得不到真确结果?publicclassTest{publicstaticintn=8;//棋盘行列数publicstaticintcount=0;//皇后解法个数publicstaticQueen[]stack=newQueen[n];//皇后栈publicstaticinttop=0;//栈顶//利用栈publicstaticvoidsearch3(){//cur行if(top==n){count++;}else{for(inti=0;i<n;i++){//顺序

递归-(已解决)自己用java写的八皇后问题算法,可是不行,求告知原因

问题描述 (已解决)自己用java写的八皇后问题算法,可是不行,求告知原因 public class Test { public static void main(String[] args) { Empress a=new Empress(); a.find(0,0); System.out.println(a.map); } } class Empress{ public int[][] arry=new int[8][8]; public int map=0; public boolean