八皇后问题

基本资料同理不罗列了。

不过我发现网上讲这个问题的文章很多,真正讲的清晰易懂的极少,还有些代码乱的一塌糊涂。这里贴篇我认为还可以的文章供参考:

回溯法求解八皇后问题


因为这个问题太著名,之前经常在眼睛前面晃过去,所以尽管《数据结构》为此节标了两个星号,我还是忍不住自己实现了下。

有趣的几点感受:

1,虽然这一节放在树这一章里讲,但压根不需要用到树这种数据结构,算是取其神舍其形吧。

2,回溯的概念大体不难理解,但具体用什么形式实现?我想了好久,以至于最后折腾出一堆废代码来(参考第二份源码)。其实,同样根本不需要自己实现,回溯的动作早已隐含在for循环里了。

3,关于此算法的优化改进,网上很多,这里暂时就先不深究了,留待日后学习。

目前最快的N皇后问题算法


以下是简洁版的代码,运行结果较长,就不贴出了,效率很一般,不过是自己按oop风格写的,也不太难懂:

#include <iostream>
#include <cmath>

using std::cin;
using std::cout;
using std::endl;

class CEightQueen
{
private:
    int *result;    //记录n皇后问题解的动态数组指针
    int length;     //皇后数

    void PrintResult(); //输出一个解

public:
    
    int total;          //解总数

    CEightQueen(int n);
    ~CEightQueen();

    void Put(int start_row);         //在某行开始落子
    int Check(int row, int column); //测试某行某列落子是否合法
};

CEightQueen::CEightQueen(int n) 
                : total(0)
{
    result = new int[n];  
    length = n;
}

CEightQueen::~CEightQueen()
{
    if (result != NULL)
    {
        delete result;
        result = NULL;
    }
}

void CEightQueen::Put(int start_row)
{
    for(int col=0; col<length; ++col)
    {
        if (1 == Check(start_row, col))
        {
            result[start_row] = col;            //落子并记录

            if ((length - 1) == start_row)      //已到最后一行,注意边界行列数比实际行列数少1
            {
                PrintResult();
                total++;
            }
            else
            {
                Put(start_row + 1);
            }
        }
        else
        {}
    }  
}

int CEightQueen::Check(int row, int column)
{
    if (0 == row) 
    {
        return 1;     //第0行随便放永远合法
    }
    else
    {
        for (int i=0; i<row; ++i)   //0 ~ row-1 行已落子均需与新落子不冲突
        {
            if ((column == result[i]) || (abs(row - i) == abs(column - result[i])))
            {
                return 0;   //不合法
            }
            else
            {}
        }

        return 1;   //经过前面所有检验后,合法
    }  
}

void CEightQueen::PrintResult()
{
    for(int i=0; i<length; ++i)
    {
        cout<<result[i]<<" ";
    }
    cout<<endl;
}

int main()
{
    int n;
    cout<<"请输入皇后数:";
    cin>>n;

    CEightQueen eq(n);
    eq.Put(0);
    cout<<"total : "<<eq.total<<endl;
}


以下是一份有意思的充满冗余的代码。

可以看到,我用记录参数,令函数返回,然后判断返回值决定是继续执行还是结束的做法,实在多此一举:

#include <iostream>
#include <cmath>

using std::cin;
using std::cout;
using std::endl;

class CEightQueen
{
private:
    int *result;    //记录n皇后问题解的动态数组指针
    int length;     //皇后数

    void PrintResult(); //输出一个解

public:
    //int current_row;    //回溯到的行数
    //int current_column; //回溯到的列数
    
    int total;          //解总数

    CEightQueen(int n);
    ~CEightQueen();

    int Put(int start_row);         //在某行开始落子
    int Check(int row, int column); //测试某行某列落子是否合法
};

CEightQueen::CEightQueen(int n) 
                :   //current_row(0),
                    //current_column(0),
                    total(0)
{
    result = new int[n];  
    length = n;

    //for(int i=0; i<length; ++i)
    //{
    //    result[i] = -1;     //初始为-1表示未落子
    //}
}

CEightQueen::~CEightQueen()
{
    if (result != NULL)
    {
        delete result;
        result = NULL;
    }
}

int CEightQueen::Put(int start_row)
{
    for(int col=0; col<length; ++col)
    {
        if (1 == Check(start_row, col))
        {
            result[start_row] = col;            //落子并记录

            if ((length - 1) == start_row)      //已到最后一行,注意边界行列数比实际行列数少1
            {
                PrintResult();
                total++;
            }
            else
            {
                Put(start_row + 1);
            }
        }
        //else
        //{
        //    if ((length -1) == col) //此行直到最后一列均不合法
        //    {
        //        //上一行的落子导致下一行无解,需取消上一行结果,从上一行的下一格开始继续落子判断
        //        //此处返回上一行行数重新Put
        //        current_row = start_row - 1;
        //        current_column = result[start_row - 1] + 1;
        //        return 0;   //返回0,表示未结束
        //    }
        //    else
        //    {
        //        //continue
        //    }
        //}
    }

    return 1;   //finish
}

int CEightQueen::Check(int row, int column)
{
    if (0 == row) 
    {
        return 1;     //第0行随便放永远合法
    }
    else
    {
        for (int i=0; i<row; ++i)   //0 ~ row-1 行已落子均需与新落子不冲突
        {
            if ((column == result[i]) || (abs(row - i) == abs(column - result[i])))
            {
                return 0;   //不合法
            }
            else
            {}
        }

        return 1;   //经过前面所有检验后,合法
    }  
}

void CEightQueen::PrintResult()
{
    for(int i=0; i<length; ++i)
    {
        cout<<result[i]<<" ";
    }
    cout<<endl;
}

int main()
{
    int n;
    cout<<"请输入皇后数:";
    cin>>n;

    CEightQueen eq(n);
    //while( 0 == eq.Put(eq.current_row, eq.current_column));
    eq.Put(0);
    cout<<"total : "<<eq.total<<endl;
}


最后再贴一份百度贴吧里copy来的代码,写的比较简洁、悬乎,留待日后有空研究。

#include "stdafx.h"
#include <stdio.h>

FILE *fp; 
int ha[9], i, a[24], b[24], c[24]; 

void work(int i) 
{
    int o, j; 
    for(j=1; j<9; j++)
    {
        if(a[j+7]==0 && b[i-j+7]==0 && c[j+i+7]==0) 
        {
            ha[i] = j; 
            a[j+7] = 1; 
            b[i-j+7] = 1; 
            c[j+i+7] = 1; 

            if (i < 8)
            {
                work(i + 1); 
            }             
            else 
            {
                for(o = 1; o < 9; o++) 
                {
                    fprintf(fp, "%d ", ha[o]); 
                }
                fprintf(fp, "\n"); 
            }

            a[j+7] = 0; 
            b[i-j+7] = 0; 
            c[j+i+7] = 0; 
        } 
    }      
} 

int main() 
{
    int k; 
    for(k=0; k<=23; k++)
    {
        a[k] = 0;
        b[k] = 0;
        c[k] = 0; 
    }
    
    fp = fopen("eight.txt","w"); 
    work(1); 
    fclose(fp); 
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值