NCSTOJ 1361 八皇后

NCSTOJ 1361 八皇后

在8*8的棋盘上,放置8个皇后,使两两之间互不攻击。满足:
1、不在同一列
2、不在同一行
3、不在同一对角线
输入:

输出:
按给定顺序和格式输出所有八皇后问题的解
方案1:1 5 8 6 3 7 2 4
方案2:1 6 8 3 7 4 2 5

一个回溯问题:递归函数讲不再递归调用它自己,而是返回上一层调用

主要问题是怎么解决对角线的情况(矩阵下标从0开始,本题要求从1开始,效果一样)

主对角线:

[ 0 1 2 3 4 5 6 7 − 1 0 1 2 3 4 5 6 − 2 − 1 0 1 2 3 4 5 − 3 − 2 − 1 0 1 2 3 4 − 4 − 3 − 2 − 1 0 1 2 3 − 5 − 4 − 3 − 2 − 1 0 1 2 − 6 − 5 − 4 − 3 − 2 − 1 0 1 − 7 − 6 − 5 − 4 − 3 − 2 − 1 0 ] 一 个 格 子 ( x , y ) , 其 主 对 角 线 可 以 用 y − x ( x − y 效 果 相 同 ) 表 示 \left[ \begin{matrix} 0 &1&2&3&4&5&6&7 \\ -1 & 0 &1&2&3&4&5&6 \\ -2&-1&0&1&2&3&4&5\\ -3&-2&-1&0&1&2&3&4\\ -4&-3&-2&-1&0&1&2&3\\ -5&-4&-3&-2&-1&0&1&2\\ -6&-5&-4&-3&-2&-1&0&1\\ -7&-6&-5&-4&-3&-2&-1&0 \end{matrix} \right]\\ 一个格子(x,y),其主对角线可以用y-x(x-y效果相同)表示 0123456710123456210123453210123443210123543210126543210176543210(x,y)线yx(xy)

副对角线:

[ 0 1 2 3 4 5 6 7 1 2 3 4 5 6 7 8 2 3 4 5 6 7 8 9 3 4 5 6 7 8 9 10 4 5 6 7 8 9 10 11 5 6 7 8 9 10 11 12 6 7 8 9 10 11 12 13 7 8 9 10 11 12 13 14 ] 一 个 格 子 ( x , y ) , 副 对 角 线 可 以 用 x + y 表 示 \left[ \begin{matrix} 0&1&2&3&4&5&6&7\\ 1&2&3&4&5&6&7&8\\ 2&3&4&5&6&7&8&9\\ 3&4&5&6&7&8&9&10\\ 4&5&6&7&8&9&10&11\\ 5&6&7&8&9&10&11&12\\ 6&7&8&9&10&11&12&13\\ 7&8&9&10&11&12&13&14 \end{matrix} \right]\\ 一个格子(x,y),副对角线可以用x+y表示 0123456712345678234567893456789104567891011567891011126789101112137891011121314(x,y)线x+y

#include<cstdio>
int c[15];		//c数组保存皇后存放位置
int cnt=0;
void queen(int cur)
{
    if(cur==9)		//因为最后还会执行cur+1所以终止条件为9
    {
        printf("方案%d:",++cnt);
        for(int k=1;k<=8;++k)
            printf("%d ",c[k]);
        printf("\n");
        return;
    }
    for(int i=1;i<=8;++i)         //1到8列
    {
        int ok=1;
        c[cur]=i;				//放在第cur行第i列
        for(int j=1;j<cur;++j)
        {
            if(c[cur]==c[j]||c[cur]-cur==c[j]-j||cur+c[cur]==j+c[j])//列,主对角线,副对角线
            {
                ok=0;
                break;
            }
        }
        if(ok)
            queen(cur+1);
    }
}
int main()
{
    queen(1);
    return 0;
}

改进:

用一个二维数组book[3][20] 来判断当前位置的列对角线是否存在其他的皇后

book[0][i] 代表第i列有没有其他皇后

book[1][pos+i] 代表当前副对角线有没有其他皇后

book[2][pos-i+8] 代表当前主对角线有没有其他皇后(其中加8是因为pos-i可能为负)

数组中的第一维0,1,2并不代表行或列,只是表明0存放列数据,1存放副对角线数据,2存放主对角线数据

#include<cstdio>
int cnt=0,c[15],book[3][20]; 	//c数组保存皇后存放位置

void queen(int pos)
{
    if(pos==9)					//因为最后还会执行cur+1所以终止条件为9
    {
        printf("方案%d:",++cnt);
        for(int k=1;k<=8;++k)	//存放位置,k代表行,c[k]代表列
            printf("%d ",c[k]);
        printf("\n");
        return;
    }
    for(int i=1;i<=8;++i)
    {
        if(!book[0][i]&&!book[1][pos+i]&&!book[2][pos-i+8])	//列,副对角线,主对角线
        {
            c[pos]=i;
            book[0][i]=book[1][pos+i]=book[2][pos-i+8]=1;   //标记该位置的列,对角线不可用
            queen(pos+1);
            book[0][i]=book[1][pos+i]=book[2][pos-i+8]=0;	//回溯完成,返回上一层调用,回溯前的皇后被拿走,要求恢复原状态
        }
    }
}

int main()
{
    queen(1);
    return 0;
}

运行完成后有92种可行方案

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值