八皇后递归求解

原创 2015年07月09日 14:34:17

八皇后,很经典的一道题目了,即在棋盘上摆满八个皇后,互相不在同一行同一列同一对角线上,问有几种摆法。其实可以扩展为n(n >= 4)皇后问题。以前被这种题目吓尿过,现在想来当时实在可笑。

有了刷leet的经验,这道题跟leet上求电话号码组合的题目何其类似,只是多了不能同行同列同对角线的判断。于是套用该题结构走起,比较顺利的做了出来,不过有bug导致丢解,原因为当最后一列的数据置1后如果其下一层无解的话,递归回来后会直接跳出循环导致此时置的1没有还原回去,造成之后的冲突判断错误。解决只需在每次循环后都全置本层数据为0即可,因为如果是解的话,根本走不到全置0的语句,当打印出解后再依次将本层置0回退,正好满足要求。

此程序不太满意的地方为冲突检测的方法有些呆笨。

bool isConfilctQueen(int **martix, int row, int column, int count) {
    bool result = false;
    for (int i = 0; i < count; i++) { //行检测
        if (i == column) continue;
        if (martix[row][i] == 1)
            return true;
    }
    for (int i = 0; i < count; i++) { //列检测
        if (i == row) continue;
        if (martix[i][column] == 1)
            return true;
    }
    for (int i = 1; i < count; i++) { //对角线检测,以目标点为中心,对角线相对长度一次检测四个角
        if (row - i >= 0 && column - i >= 0) { //左上角
            if (martix[row - i][column - i] == 1)
                return true;
        }
        if (row - i >= 0 && column + i < count) { //右上角
            if (martix[row - i][column + i] == 1)
                return true;
        }
        if (row + i < count && column - i >= 0) { //左下角
            if (martix[row + i][column - i] == 1)
                return true;
        }
        if (row + i < count && column + i < count) { //右下角
            if (martix[row + i][column + i] == 1)
                return true;
        }
    }
    
    return result;
}
void backtrackingQueen(int **martix, int n, int count, int *num) {
    if (n == count) {
        *num += 1;
        printf("第%d组解:\n", *num);
        for (int i = 0; i < count; i++) {
            for (int j = 0; j < count; j++)
                printf("[%d]", martix[i][j]);
            printf("\n");
        }
        printf("\n");
        return;
    }
    for (int i = 0; i < count; i++) { //此循环里2个memset的位置有玄妙
//        memset(martix[n], 0, sizeof(int) * count);
        martix[n][i] = 1;
        if (!isConfilctQueen(martix, n, i, count))
            backtrackingQueen(martix, n + 1, count, num);
        memset(martix[n], 0, sizeof(int) * count);
    }
}
int nQuenn(int count) {
    if (count < 4) {
        printf("Error! n < 4\n");
        return 0;
    }
    int **martixQuenn = (int **)malloc(sizeof(int *) * count);
    for (int i = 0; i < count; i++) {
        martixQuenn[i] = (int *)malloc(sizeof(int) * count);
        memset(martixQuenn[i], 0, sizeof(int) * count);
    }
    
    int n = 0;
    int num = 0;
    backtrackingQueen(martixQuenn, n, count, &num);
    
    for (int i = 0; i < count; i++)
        free(martixQuenn[i]);
    free(martixQuenn);
    
    return num;
}



后来又重新写了一遍,重点在于优化了下冲突判断的函数:目标点跟之前置为1的点斜率不成1或-1就说明不是对角线,另我的程序是按列生成的,所以隐含了下一个点不在同一列的条件,即不用判断是否同列,所以只要判断是否同行就行。

程序如下,n可以控制要输出几个皇后:

void printNQueens(int **matrix, int n, int row, int column, int *count) {
    if (row >= n || column >= n)
        return;
    
    bool flag = true;
    for (int i = 0; i < n && flag; i++) {
        
        for (int j = 0; j < n && flag; j++) {
            if (matrix[i][j] == 1) {
                if (row == i || abs(row - i) == abs(column - j)) {
                    flag = false;
                }
            }
        }
        
    }
    
    if (flag) {
        matrix[row][column] = 1;
        
        if (column == n - 1) { //最后一列到达,开始打印
            *count += 1;
            printf("第%d组解:\n", *count);
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    printf("%d ", matrix[i][j]);
                }
                printf("\n");
            }
            printf("\n");
            
            matrix[row][column] = 0;
            
            return;
        }
    }
    
    if (flag) {
        printNQueens(matrix, n, 0, column + 1, count);
        matrix[row][column] = 0;
    }

    printNQueens(matrix, n, row + 1, column, count);
}
bool nQueens(int n) {
    bool result = true;
    
    int **martrix = (int **)calloc(n, sizeof(int *));
    for (int i = 0; i < n; i++) {
        martrix[i] = (int *)calloc(n, sizeof(int));
        for (int j = 0; j < n; j++)
            martrix[i][j] = 0;
    }
    
    int *count = (int *)calloc(1, sizeof(int));
    int row = 0, column = 0;
    
    printNQueens(martrix, n, row, column, count);
    printf("all nQueens are %d.\n\n", *count);
    
    for (int i = 0; i < n; i++) {
        free(martrix[i]);
        martrix[i] = NULL;
    }
    free(martrix);
    martrix = NULL;
    
    free(count);
    count = NULL;
    
    return result;
}


八皇后问题 递归求解

八皇后问题递归求解          首先介绍一下八皇后问题,八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇...
  • dliyuedong
  • dliyuedong
  • 2013年10月04日 16:23
  • 5034

数据结构学习笔记(12.递归的应用之八皇后回溯算法)

本节知识点:1.递归与回溯:   a.回溯算法的基本思想:从问题的某一种状态出发,搜索可以到达的所有状态。当某个状态到达后,可向前回退,并继续搜索其他可达状态。当所有状态都到达后,回溯算法结束!   ...
  • qq418674358
  • qq418674358
  • 2014年04月16日 23:17
  • 4401

八皇后问题递归解法

八皇后问题
  • u012842664
  • u012842664
  • 2015年08月02日 18:25
  • 3480

八皇后问题(最简单的递归解法)

题目 原文: Write an algorithm to print all ways of arranging eight queens on a chess board so that...
  • yangting09032214
  • yangting09032214
  • 2015年08月27日 15:24
  • 1714

理解使用递归及堆栈的算法处理八皇后问题

八皇后算法
  • lnnnd
  • lnnnd
  • 2016年05月26日 15:39
  • 4133

八皇后问题(典型的递归回溯)

八皇后 : 这个代码只是输出一共有多少种摆放的个数。如果想要输出他摆放的不同方法 只需要在递归出口的时候用两个for循环输出棋盘即可。 目的在于每行,每列,以及对角线上都只能放置一个皇后,所...
  • lp15203883326
  • lp15203883326
  • 2016年09月07日 20:27
  • 994

八皇后求解方法(递归求解)

问题描述         国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。...
  • q623702748
  • q623702748
  • 2016年04月10日 01:11
  • 554

C#递归求解八皇后

    很久没更新Blog了,开始玩玩算法吧,用递归写了一下八皇后,不知道是不是最优方案,继续研究其他的解法,尝试下回朔,代码如下    using System;using System.Colle...
  • Red_angelX
  • Red_angelX
  • 2007年02月26日 15:51
  • 1431

八皇后递归求解问题

昨天在同济医学院参加DeNA宣讲及笔试,最后一题为八皇后递归求解填空,不懂。 今天在上网搜索并认真思考后,在此做一个总结。 求解思路: 棋盘为8行8列,从第0行开始放第一个皇后,设放在第 i 列...
  • sinkary
  • sinkary
  • 2011年11月24日 12:02
  • 765

递归算法学习系列之八皇后问题

1.引子    中国有一句古话,叫做“不撞南墙不回头",生动的说明了一个人的固执,有点贬义,但是在软件编程中,这种思路确是一种解决问题最简单的算法,它通过一种类似于蛮干的思路,一步一步地往前走,...
  • GarfieldEr007
  • GarfieldEr007
  • 2015年09月29日 21:33
  • 2233
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:八皇后递归求解
举报原因:
原因补充:

(最多只允许输入30个字)