zoukankan      html  css  js  c++  java
  • DFS(三):八皇后问题

    【例1】八皇后问题。

          在一个8×8国际象棋盘上,放置8个皇后,每个皇后占一格,要求皇后间不会出现相互“攻击”的现象,即不能有两个皇后处在同一行、同一列或同一对角线上。问共有多少种不同的放置方法?

          (1)编程思路。

          在八皇后问题中,由于任意两个皇后不同行,因此可以将布局表示为一维数组chess[8]。数组的下标i表示棋盘上的第i行,chess[i]的值表示皇后在第i行所放的位置。如chess[1]=5,表示在棋盘的第1行的第5列放一个皇后。

          为了寻找满足要求的布局chess,可依次产生部分布局(chess[0]),(chess[0]、chess[1]),…,直至最后产生出完整布局(chess[0]、chess[1]、…、chess[7])。每一步都要求保证它们是在不同列和不同对角线上。可采用深度优先搜索算法完成。

          (2)源程序。

    #include <iostream>

    using namespace std;

    void show_chess(void);

    int check(int n);

    void putchess(int n);

    int chess[8];

    int main()

    {

        cout<<"All Results are :"<<endl;

        putchess(0);

        return 0;

    }

    // 递归函数:在从第n行开始放皇后

    void putchess(int n)

    {

        int i;

        if (n<8)

        {

          for (i = 0; i <8; i++)      // 将第n行从第一格(i)开始往下放

          {

             chess[n] = i;

             if (check(n) == 1)       // 若可放,则检查是否放满

             {

                if (n == 7)

                   show_chess();     // 若已放满到8行时,则表示找出一种解,打印出来

                else

                   putchess(n + 1);   // 若没放满则放下一行 putchess(n+1)

             }

         }

       }

    }

    // 根据前面几行的子,检查第n行所放的皇后是否合法

    int check(int n)

    {

        int i;

        for (i = 0; i <= n - 1; i++)

           if (chess[n] == chess[i] + (n - i) ||chess[n] == chess[i] - (n - i) ||chess[n] == chess[i] )

                return 0;

        return 1;

    }

    // 函数:打印结果

    void show_chess(void)

    {

        static int count = 0;

        cout<<"************* 第"<<++count<<"种 *************"<<endl;

        for(int i=0; i<8; i++)

        {

             for(int j=0; j<8; j++)

                if (j==chess[i]) cout<<"1 ";

                         else  cout<<"0 ";

             cout<<endl;

        } 

    }


    【例2】棋盘问题(POJ 1321)。
    Description

    在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。
    Input

    输入含有多组测试数据。
    每组数据的第一行是两个正整数,n k,用一个空格隔开,表示了将在一个n*n的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n
    当为-1 -1时表示输入结束。
    随后的n行描述了棋盘的形状:每行有n个字符,其中 # 表示棋盘区域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
    Output

    对于每一组数据,给出一行输出,输出摆放的方案数目C (数据保证C<2^31)。
    Sample Input

    2 1
    #.
    .#
    4 4
    ...#
    ..#.
    .#..
    #...
    -1 -1
    Sample Output

    2
    1

          (1)编程思路。

          在棋盘问题中,棋子摆放的位置只能是#, 且不能同行和同列。由于在深度优先搜索中采用按行递增的顺序来搜索的,这样每次递归下一行,所以每一行不会有冲突,不可能出现同行的情况。只需保证不同列,为判断某一列上是否有其他棋子,可定义一个数组visit[]来保存列的访问状态,visit[i]=true表示第i列上放置有棋子;visit[i]=false表示第i列上未放置棋子。

          (2)源程序1。

    #include <iostream>

    using namespace std;

    bool visit[20];

    char map[20][20];

    int ans,k,n;    // ans表示方案数,k表示棋子数目,n表示棋盘的大小

    void DFS(int row,int num)   // 逐行搜索,row为当前搜索行,num为已填充的棋子数

    {

        if(num>=k)   // 判断是否棋子已经放完,如果放完,记录方案数加1

        {

            ans++;

            return;

        }

        for(int i=row;i<n;i++)    

        {

            for(int j=0;j<n;j++)

            {

                if(!visit[j] && map[i][j]=='#')  // 如果该列没放棋子且该位置为棋盘,那么在这里放上棋子

                {

                    visit[j]=true;             // 标记该列上有棋子

                    DFS(i+1,num+1);   // 搜索下一行放下一个棋子

                    visit[j]=false;           // 修改标记后递归回来要及时复原

                }

            }

        }

    }

    int main()

    {

           int i;

          while (cin>>n>>k)

          {

              if (n==-1&&k==-1)

                  break;

              for (i=0;i<n;i++)

                 visit[i]=false;

              for (i=0;i<n;i++)

                cin>>map[i];

            ans=0;

            DFS(0,0);

            cout<<ans<<endl;

        }

        return 0;

    }

    (3)源程序2。

    #include <iostream>
    using namespace std;
    bool visit[20];
    char map[20][20];
    int ans,k,n;   // ans表示方案数,k表示棋子数目,n表示棋盘的大小
    void DFS(int row,int num)    // 逐行搜索,row为当前搜索行,num为已填充的棋子数
    {
        if(num==k)
       {
           ans++;
           return;
        }
        if (row>=n) return ;
        for(int j=0;j<n;j++) // 当前行放一个棋子
        {
            if(!visit[j] && map[row][j]=='#')
           {
               visit[j]=true;
               DFS(row+1,num+1);
               visit[j]=false;
            } 
         }
        DFS(row+1,num); // 当前行不放棋子
    }
    int main()
    {
         int i;
         while (cin>>n>>k)
         {
             if (n==-1&&k==-1)
                 break;
             for (i=0;i<n;i++)
                 visit[i]=false;
             for (i=0;i<n;i++)
                 cin>>map[i];
             ans=0;
            DFS(0,0);
            cout<<ans<<endl;
        }
        return 0;
    }

  • 相关阅读:
    加了一句话
    由于数据库 'XXX' 离线,无法打开该数据库。
    Linux命令list
    js 数组去重
    JSON.parse(JSON.stringify()) 实现对对象的深度拷贝,从而互不影响
    docker
    Node child_process Study.2
    node assert模块 Study.1
    git 合并本地分支到远程分支
    Vue 项目搭建
  • 原文地址:https://www.cnblogs.com/cs-whut/p/11155679.html
Copyright © 2011-2022 走看看