zoukankan      html  css  js  c++  java
  • 八皇后问题

    1213:八皇后问题


    时间限制: 1000 ms         内存限制: 65536 KB
    提交数: 5367     通过数: 1856 

    【题目描述】

    在国际象棋棋盘上放置八个皇后,要求每两个皇后之间不能直接吃掉对方。

    【输入】

    (无)

    【输出】

    按给定顺序和格式输出所有八皇后问题的解(见样例)。

    【输入样例】

    (无)

    【输出样例】

    No. 1
    1 0 0 0 0 0 0 0 
    0 0 0 0 0 0 1 0 
    0 0 0 0 1 0 0 0 
    0 0 0 0 0 0 0 1 
    0 1 0 0 0 0 0 0 
    0 0 0 1 0 0 0 0 
    0 0 0 0 0 1 0 0 
    0 0 1 0 0 0 0 0 
    No. 2
    1 0 0 0 0 0 0 0 
    0 0 0 0 0 0 1 0 
    0 0 0 1 0 0 0 0 
    0 0 0 0 0 1 0 0 
    0 0 0 0 0 0 0 1 
    0 1 0 0 0 0 0 0 
    0 0 0 0 1 0 0 0 
    0 0 1 0 0 0 0 0 
    ...以下省略

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


    国际象棋中,皇后可以横斜直三个方向走,步数不受限制,是最强的棋子。
    放在本题中考虑,粗略分析,在8*8的棋盘中,要放下八个皇后,每个皇后一定异行异列,才能满足题目要求。

    经过以上分析,很明显,每两个皇后之间的位置关系是(用i表示行,j表示列):

    ai≠bi,aj≠bj(不同行列),|ai-bi|
    ≠|aj-bj|,|ai+bi|≠|aj+bj|(不同斜线);

    即不同行不同列不同斜线。
    好的,基本思路很简单,接下来是算法实现。别看思路简单,其实这是一道经典的难题。



    算法分析:
    这是一个有点dp的搜索算法。呃。。。回溯算法。
    初步思路是设置一个int型一维数组储存皇后的位置;
    接下来,就是完成搜索函数的功能了。

    逐行放置棋子,同时检查是否符合两棋子之间的条件关系,直到放完8个棋子。
    但是我们如何判断两个皇后之间的关系呢?这里是本题的关键。

    这里有一种便捷的方法,因为根据算法每个棋子必定异行,那就设置3个数组,表达某处被占地整列,整左斜线,整右斜线
    上的格子不得放置下一枚棋子。

    为方便起见,我们设置一个关键二维数组vis[3][(此处应大于16,因为最值为i+j=16)].
    首先检查当前列,行,斜线上能否放置:
    if(vis[0][i]==0&&vis[1][step+i]==0&&vis[2][step-i+8]==0)//注意:vis[2]由于数组会越界,在行列值相减后必须加至大于0;
    
    如果是,放置棋子,并声明棋子所在行,列,斜线全部无法放置棋子:
    vis[0][i]=1;
    vis[1][i+step]=1;
    vis[2][step-i+8]=1;
    a[step]=i;

        接下来,搜索下一颗棋子:

    dfs(step+1);
    

       完事了以后要销毁证据/滑稽(回溯):

    vis[0][i]=0;
    vis[1][i+step]=0;
    vis[2][step-i+8]=0;
    

       肥肠好,到这里搜索部分就基本完成了。

       加入递归边界:

    if(step==9)
        {
            tot++;
            for(int i=1;i<=8;i++)
                ans[tot][i]=a[i];//设置传值数组,将所有临时数据传入此数组。
            return;
        }
    

     大功告成!

       说实话挺简单的,但是我怎么写都是错的,最后还是去看了一眼答案。。。虽说思路一样吧。。。但是为什么我就是错了(蓝瘦)??? 

       没什么需要具体分析的。

       样例代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #define N 100
    using namespace std;
    int ans[N][N],a[N];
    int vis[N][N];
    int tot;
    void dfs(int step)
    {
        if(step==8+1)
        {
            tot++;
            for(int i=1;i<=8;i++)
                ans[tot][i]=a[i];
            return;
        }
        for(int i=1;i<=8;i++)
        {
            if(vis[0][i]==0&&vis[1][step+i]==0&&vis[2][step-i+8]==0)
            {
                vis[0][i]=1;
                vis[1][i+step]=1;
                vis[2][step-i+8]=1;
                a[step]=i;
                dfs(step+1);
                vis[0][i]=0;
                vis[1][i+step]=0;
                vis[2][step-i+8]=0;
            }
        }
    }
    int main()
    {
        dfs(1);
        for(int t=1;t<=tot;t++)
        {
            printf("No. %d
    ",t);
            for(int i=1;i<=8;i++)
            {
                for(int j=1;j<=8;j++)
                {
                    if(ans[t][j]==i)
                        cout<<"1 ";
                    else
                        cout<<"0 ";
                }
                cout<<endl;
            }
        }
        return 0;
    }
    

    2019-02-05 20:59:02

  • 相关阅读:
    手机号 验证(正则)
    静态库相关
    添加友盟SDK,实现新浪分享和微信朋友圈分享的关键代码
    删除Mac 系统中多出得MobileBackups 文件夹
    浏览器判断检测手机中是否安装了ios/android客户端程序
    浏览器判断是否安装了ios/android客户端程序
    自定义TextField的删除按钮
    应用崩溃日志解析
    关于UITextView的一些问题
    关于UIColor这个类的一些不知道的事
  • 原文地址:https://www.cnblogs.com/DarkValkyrie/p/10353129.html
Copyright © 2011-2022 走看看