八皇后问题——枚举法,回溯法

问题描述

在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。(摘自百度百科。。。)

枚举法

别的不说了,直接上代码

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

void print_(int qu[])        //输出显示函数
{
    int i, j;
    for(i = 0; i < 8; i++){
        for(j = 0; j < qu[i]; j++){
            printf("%c", 6);
        }
        printf("%c", 12);
        for(j = 0; j < 8-qu[i]-1; j++){
            printf("%c", 6);
        }
        printf("\n");
    }
}

bool is(int qu[])              //判断是否会冲突
{
    int i, j;
    for(i = 0; i < 8; i++)
    {
        for(j = 0; j < i; j++)
        {
            if(qu[i] == qu[j]) return false;
            if(abs(qu[i]-qu[j]) == abs(i-j)) return false;
        }
    }
    return true;
}

int main()
{
    int a[10]={0};
    int i, number = 1;
    for(a[0] = 0; a[0] < 8; a[0]++)     //依次枚举8行。。。
    for(a[1] = 0; a[1] < 8; a[1]++)
    for(a[2] = 0; a[2] < 8; a[2]++)
    for(a[3] = 0; a[3] < 8; a[3]++)
    for(a[4] = 0; a[4] < 8; a[4]++)
    for(a[5] = 0; a[5] < 8; a[5]++)
    for(a[6] = 0; a[6] < 8; a[6]++)
    for(a[7] = 0; a[7] < 8; a[7]++)
    {
        if(is(a)){
            printf("Kase %d:\n", number++);
            print_(a);
            printf("\n");
        }
    }
    return 0;
}

回溯法

#include<cstdio>
#include<cmath>
using namespace std;

void showQueen(int queenArr[], int n, int nSolution)    //输出显示函数
{
    printf("Case %d:\n", nSolution);
    for(int i = 0; i < n; i++){
        for(int j = 0; j < queenArr[i]; j++){
            printf("%c", 6);
        }
        printf("%c", 12);
        for(int j = 0; j < n - queenArr[i] - 1; j++){
            printf("%c", 6);
        }
        printf("\n");
    }
}

bool isClash(int queenArr[], int nRow)
{
    for(int iRow = 0; iRow < nRow; iRow++){          ///检测当前第nRow行的摆放是否与其前面第iRow行冲突
        if(queenArr[iRow] == queenArr[nRow]){           ///在同一列上,冲突
            return true;
        }
        if(abs(queenArr[iRow]-queenArr[nRow]) == abs(iRow-nRow)){  ///在对角线上,冲突
            return true;
        }
    }
    return false;
}

void putQueen(int queenArr[], int nRow, int nLen, int &nSolution)  ///已放完前nRow行的皇后,正在放第nRow行的皇后
{
    for(int i = 0; i < nLen; i++){
        queenArr[nRow] = i;                                    ///把皇后放在第nRow行的第i列
        ///检查冲突,如果有冲突,忽略从第nRow行开始以下的所有皇后摆放
        if(!isClash(queenArr, nRow)){
            if(nRow == nLen - 1){   ///全部8行已经摆放完毕,且无冲突
                nSolution++;
                showQueen(queenArr, nLen, nSolution);
            }
            else{
                putQueen(queenArr, nRow + 1, nLen, nSolution);  ///放下一行皇后的位置
            }
        }
    }
}

int main()
{
    int queenArr[20];
    int nSolution = 0;           ///解法数量
    putQueen(queenArr, 0, 8, nSolution);   ///从第0行开始放,8皇后问题
    return 0;
}

但在有些问题中,回溯法常常会产生大量的重复计算,导致TLE,可用动态规划来解决。。。

发布了8 篇原创文章 · 获赞 3 · 访问量 2033
展开阅读全文

位运算解决8皇后问题,怎么输出解

10-07

``` #include <stdio.h> #include <stdlib.h> int sum = 0,,upperlim = (1 << 8) - 1; test(short row, short ld, short rd) { if (row != upperlim) { // row,ld,rd进行“或”运算,求得所有可以放置皇后的列,对应位为0, // 然后再取反后“与”上全1的数,来求得当前所有可以放置皇后的位置,对应列改为1 // 也就是求取当前哪些列可以放置皇后 short pos = upperlim & ~(row | ld | rd);//所有可以放的位置 while (pos != 0) // 0 -- 皇后没有地方可放,回溯 { // 拷贝pos最右边为1的bit,其余bit置0 // 也就是取得可以放皇后的最右边的列 short p = pos & -pos;//最右边的位置 // row + p,将当前列置1,表示记录这次皇后放置的列。 // (ld + p) << 1,标记当前皇后左边相邻的列不允许下一个皇后放置。 // (ld + p) >> 1,标记当前皇后右边相邻的列不允许下一个皇后放置。 // 此处的移位操作实际上是记录对角线上的限制,只是因为问题都化归 // 到一行网格上来解决,所以表示为列的限制就可以了。显然,随着移位 // 在每次选择列之前进行,原来N×N网格中某个已放置的皇后针对其对角线 // 上产生的限制都被记录下来了 test(row + p, (ld + p) << 1, (rd + p) >> 1); // 将pos最右边为1的bit清零 // 也就是为获取下一次的最右可用列使用做准备, // 程序将来会回溯到这个位置继续试探 pos -= p; } } else { // row的所有位都为1,即找到了一个成功的布局,回溯 sum++; printf("这是第%d种解决方案.\n",sum); } } int main() { test(0, 0, 0); printf("总共有 %d 种解决方法!\n\n", sum); return 0; } ``` 最近学习位运算,不过用位运算解决8皇后问题怎么输出全部解法呢 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览