八皇后问题三种实现

八皇后问题三种实现

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。计算机发明后,有多种计算机语言可以解决此问题。(摘自百度)


这里用回溯法和递归实现了3种。
1 C++ 回溯
2 C 回溯
3 C 递归实现
92组解

摆放棋子的规则是:

行从上向下,列从左到右试探。

C++回溯解法

#include <deque>
using namespace std;

static int const N = 8;
//
// 下棋位置
//
struct ChessPoint
{
    ChessPoint(){}
    ChessPoint(int x,int y)
    {
        this->x = x;
        this->y = y;
    }
    ChessPoint & operator = (ChessPoint & cp)
    {
        this->x = cp.x;
        this->y = cp.y;
        return *this;
    }
    //横坐标,列
    int x;
    //纵坐标,行
    int y;
};


static bool CanPlace(int x,int y,deque<ChessPoint> &vec)
{
    deque<ChessPoint>::iterator it = vec.begin();
    for(;it!=vec.end();it++)
    {
        if( it->x == x || 
            it->y == y || 
            it->x-x == it->y-y ||
            x-it->x == it->y-y )
        {
            return false;
        }
    }
    return true;    
}
//
// passPath - 经过的路径
// lineNum - 现在检查的行
//
bool GetFreePoint(deque<ChessPoint> &result,ChessPoint &retCP)
{
    ChessPoint cp = *result.rbegin();
    int x = 0;
    int y = 0;
    x = cp.x+1;
    y = cp.y;
    result.pop_back();
    //
    // 这一行继续查
    //
    for(;;)
    {
        if(x>=N)
        {
            if(y<0)
            {
                break;
            }
            cp = *result.rbegin();
            //
            //试探下一列;行不变
            //
            x = cp.x+1;
            y = cp.y;
            if(x>=N)
            {
                //
                // 此行已经试探完毕,回到上一行
                //
                result.pop_back();
                continue;
            }
            result.pop_back();
        }
        if(CanPlace(x,y,result))
        {
            retCP.x=x;
            retCP.y=y;
            return true;
        }
        else
        {
            x+=1;
        }
    }
    return false;
}

void queen()
{
    //
    // x -> (0 , N-1) , x 是列
    // y -> (0 , N-1) ,y 是行
    //
    int x = 0;
    int y = 0;

    //
    // 结果存放在一个vector中,有 N 个元素,每行一个
    //
    deque<ChessPoint> resultVec;

    while(1)
    {
        //
        // 出口
        //
        if(resultVec.size()==N)
        {
            break;
        }
        //
        // 判断(x,y)此点是否可以
        //
        if(CanPlace(x,y,resultVec))
        {
            //
            // 存入结果
            //
            ChessPoint pp(x,y);
            resultVec.push_back(pp);
            //
            // 行加一
            //
            y+=1;
            //
            // 列归零
            //
            x=0;
        }
        else
        {
            if(x < N)
            {
                //
                // (x,y) 此点不能匹配,移动到下一列
                //
                x+=1;
                //
                // 没有列可以选择了
                //
                if(x>=N)
                {
                    //
                    // 没有找到匹配的列,则回溯到上一行,找到一个没有经过的坐标
                    //
                    ChessPoint po;
                    if(GetFreePoint(resultVec,po))
                    {
                        x = po.x;
                        y = po.y;
                    }
                    else
                    {
                        break;
                    }
                }
            }
            else
            {
                //
                // 没有找到匹配的列,则回溯到上一行,找到一个没有经过的坐标
                //
                ChessPoint po;
                if(GetFreePoint(resultVec,po))
                {
                    x = po.x;
                    y = po.y;
                }
                else
                {
                    break;
                }
            }
        }
    }
}

C回溯解法

<span style="font-size:12px;">//
// 使用回溯法解皇后问题
// 当下一行找不到合适的位置,则返回到上一行,试探下一个位置,知道找到合适的位置;
// 当找到一个解以后,放弃这个位置,回溯找下一个合适的位置,直到找不到合适的位子,
// 就将所有解找到了。
//
//
// 要放8个皇后
//
static const int N = 8;

//
// 已经放置的皇后个数
//
static int count = 0;

//
// 解的个数
//
static int solution = 0;

//
// 下棋位置
//
struct ChessPoint
{
    ChessPoint(){}
    ChessPoint(int x,int y)
    {
        this->x = x;
        this->y = y;
    }
    ChessPoint & operator = (ChessPoint & cp)
    {
        this->x = cp.x;
        this->y = cp.y;
        return *this;
    }
    //横坐标,列
    int x;
    //纵坐标,行
    int y;
};


//
// canPlace:是否可以放置皇后呢?
// line - 行,col - 列
//
static bool CanPlace(int x,int y,unsigned char* vec)
{
    for(int i=0;i<count;i++)
    {
        if( i == y || 
            vec[i] == x || 
            i-y == vec[i]-x ||
            y-i == vec[i]-x )
        {
            return false;
        }
    }
    return true;    
}
//
// passPath - 经过的路径
// lineNum - 现在检查的行
//
static bool GetFreePoint1(unsigned char* result,ChessPoint &retCP)
{
    int x = 0;
    int y = 0;
    x = result[count-1]+1;
    y = count-1;
    count-=1;
    //
    // 这一行继续查
    //
    for(;;)
    {
        if(x>=N)
        {
            if(y<0)
            {
                break;
            }
            x = result[count-1]+1;
            y = count-1;
            if(x>=N)
            {
                count-=1;
                continue;
            }
            count-=1;
        }
        if(CanPlace(x,y,result))
        {
            retCP.x=x;
            retCP.y=y;
            return true;
        }
        else
        {
            x+=1;
        }
    }
    return false;
}
//
// printResult:打印结果
// resultVec - 结果数组
//
void printResult(unsigned char *resultVec)
{
    printf("-------%d皇后的解 第%d组---------\n",N,++solution);
    for(int i=0;i<N;i++)
    {        
        for(int j=0;j<N;j++)
        {
            if(resultVec[i]==j)
            {
                printf("1 ");                
            }
            else
            {
                printf("0 ");
            }
        }
        printf("\n");
    }

}
//优化实现
void queen1()
{
    //
    // x -> (0 , N-1) , x 是列
    // y -> (0 , N-1) ,y 是行
    //
    int x = 0;
    int y = 0;

    //
    // 结果存放在数组中,数组的索引代表行,值代表对应的列
    //
    unsigned char resultVec[N];

    while(1)
    {
        //
        // 出口
        //
        if(count == N)
        {
            printResult(resultVec);
            //
            // 继续找下一个解
            //
            ChessPoint po;
            if(GetFreePoint1(resultVec,po))
            {
                //
                // 个数减一,并且回溯
                //
                x = po.x;
                y = po.y;
            }
            else
            {
                //
                //再没有解了
                //
                break;
            }
        }
        //
        // 判断(x,y)此点是否可以
        //
        if(CanPlace(x,y,resultVec))
        {
            //
            // 存入结果
            //
            resultVec[y]=x;
            count+=1;
            //
            // 行加一
            //
            y+=1;
            //
            // 列归零,从第一列试
            //
            x=0;
        }
        else
        {
            if(x < N)
            {
                //
                // (x,y) 此点不能匹配,移动到下一列
                //
                x+=1;
                //
                // 没有列可以选择了
                //
                if(x>=N)
                {
                    //
                    // 没有找到匹配的列,则回溯到上一行,找到一个没有经过的坐标
                    //
                    ChessPoint po;
                    if(GetFreePoint1(resultVec,po))
                    {
                        x = po.x;
                        y = po.y;
                    }
                    else
                    {
                        //
                        // 找不到合适的坐标了
                        //
                        break;
                    }
                }
            }
            else
            {
                //
                // 没有找到匹配的列,则回溯到上一行,找到一个没有经过的坐标
                //
                ChessPoint po;
                if(GetFreePoint1(resultVec,po))
                {
                    x = po.x;
                    y = po.y;
                }
                else
                {
                    //
                    // 找不到合适的坐标了
                    //
                    break;
                }
            }
        }
    }
}
</span>

C 递归解法

<span style="font-size:10px;">//
// 这是教课书上的解法,递归解决。
// queen3 以每行作为一个单位
//
//
// 解的个数,最后8皇后得到92组解
//
static int solution = 0;
//
// 放几个皇后?
//
static const int N=8;
//
// 已经放置的个数,如果为8个,则找到一组解
//
static int count = 0;
//
// 这里存放一组解
//
static int result[N];
//
// canPlace:是否可以放置皇后呢?
// line - 行,col - 列
//
static bool canPlace(int line,int col)
{
    for(int i=0;i<count;++i)
    {
        if( i == line               ||
            col == result[i]     || 
            i-line==col-result[i]||
            line-i == col-result[i])
        {
            return false;
        }
    }
    return true;
}
void printResult()
{
    for(int i=0;i<N;++i)
    {
        for(int j=0;j<N;++j)
        {
            if(j == result[i])
            {
                printf("1 ");
            }
            else
            {
                printf("0 ");
            }
        }
        printf("\n");
    }
    printf("\n");
}

//
// queen3 
// line - 从哪行开始?
//
bool queen3(int line)
{
    bool bFound = false;
    //
    // 当填满的时候打印
    //
    if(count == N)
    {
        printResult();
        ++solution;
        printf("  %d \n",solution);
        //count -= 1;
    }
    //
    // 当到了最后一行的时候,运行到这里说明已经找到了一条可行的路径;
    // 而继续查找就要回退一行,然后继续下一列,因此返回false,回退一行
    //
    if(line==N)
    {
        return false;
    }
    //
    //i 代表列
    //    
    for(int i=0;i<N;i++)
    {
        if(canPlace(line,i))
        {
            result[line]=i;
            count+=1;
            if(line<N)
            {
                if(!queen3(line+1))
                {
                    count-=1;
                }
                else
                {
                    bFound = true;
                }
            }
        }
    }
    //
    // 如果没有合适的位置,则返回false,然后就会回退一行,继续试探下一个位置
    //
    if(!bFound)
    {        
        return false;
    }
    return true;
}</span>

//主函数调用:
void queen();
void queen1();
bool queen3(int line);
int _tmain(int argc, _TCHAR* argv[])
{
    queen1();
    queen();
    queen3(0);
}

每一种解法是一个文件,主函数是一个文件。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
解决八皇后问题。从第一行开始,放第一个皇后,放好皇后以后,她所在的行,列和对角线上的每一个位置就是她的管辖范围,别的皇后没有权利干涉,否则死无藏身之地。 然后,第二个皇后,从第二行的第一列开始判断所在的位置是否是别的皇后的管辖范围,找到第一个还没有被占据的位置,则将其占为己有。暂时,该皇后停在该位置。然后,第三个到第八个皇后依次从第三行,第四行,… ,到第八行的第一列开始寻求自己的位置。假如到第i个皇后时,已经没有任何位置可选,则第i-1个皇后必须往后移动进行协调,同样,假如第i-1个皇后往后移动时没有找到空位置,则第i-2个皇后必须往后移动,进行协调,当找到空位置时,暂时停下,将下一个皇后重新从第一列开始寻找空位置。重复上述过程,直到所有皇后都停下来。则得到了第一个解。要想产生所有的解,则当产生第一个解以后,第八个皇后往后移动,找下一个可以利用的空位置,找不到,则第七个皇后必须往后移动,若找到空位置则停下,第八个皇后从第八行第一列重新试探,找到空位置。一直这样,直到第一个皇后将第一行遍历完。得到的解就是所有解。 三、 概要设计: ***************型及相关变量定义***************** //位置信息型 typedef struct { int row; int col; }PosType; //皇后型 typedef struct Queen{ PosType pos; int number; //第几号皇后 }QueenType; //栈节点型 typedef struct Note{ QueenType queen; struct Note *next; }NoteType; //棋盘,某一位置chessboard[i][j]上有皇后,则该位的值变为皇后序号。同样,该皇后的势 //力范围内的位置上的值全部变为该皇后的序号。 int chessboard[8][8]; //结果集,共92种解,每一种解中记录8个位置信息。 PosType ResultSet[92][8]; //定义一个栈,保存信息 Typedef struct{ NoteType head; Int size; }QueenStack; //定义一个栈,存放皇后信息 QueenStack qstack; *************相关操作**************** //初始化棋盘,开始时每个位置上都没有皇后,值全为0;并给8个皇后编号。 void initChessboard(); //回溯求八皇后问题的所有解,皇后协调算法 void queenCoordinate(); //输出所有解 void printResult();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值