八皇后问题的递归解法与回溯优化

关于八皇后问题有很多种解法,今天只写一种利用全排列的解法,其他的一些解法看情况在整理补充。

全排列算法https://blog.csdn.net/qq_41706331/article/details/86521823
题目描述:

在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
结题思路:

对于这个问题如果采用组合数的的方式来枚举每一种情况,那么将需要C_{n*n}^{n}次枚举,效率太低。

但换个思路,考虑到每行只能放置一个皇后,每列也只能放置一个皇后,如果把n列皇后所在的行号依次写出来那么就是1~8的一个

排列。因此只要枚举1~8的所有排列,统计其中合法的方案即可,只有n!个排列,比之前的枚举优秀很多。

    #include<cstdio>
    #include<cmath>
     
    int n;
    int count=0;
    int QueenList[10];
    bool StatusTable[10]={0};
     
    void NQueen(int index)
    {
        if(index==n+1)
        {
            bool flag=true;
            int i,j;
            for(i=1;i<=n;i++)
            {
                for(j=i+1;j<=n;j++)
                   if(abs(i-j)==abs(QueenList[i]-QueenList[j]))
                       flag=false;
            }
            if(flag)
               count++;
            return;
        }
        int x;
        for(x=1;x<=n;x++)
        {
            if(StatusTable[x]==false)
            {
                QueenList[index]=x;
                StatusTable[x]=true;
                NQueen(index+1);
                StatusTable[x]=false;
            }
        }
     }
     
     int main()
     {
    //    printf("有几个皇后?");
    //     scanf("%d",&n);
    //     NQueen(1);
    //     printf("%d个皇后共有%d种合法方案\n",n,count);//我靠为什么这个编译器打印汉字是问号???
        printf("how many Queens?\t");
        scanf("%d",&n);
        NQueen(1);
        printf("there are %d schemes of %d Queens.\n",count,n);
         
         return 0;
     
     }

事实上,当已经放置了一部分皇后时,可能剩余的皇后无论怎样放置都不可能合法,这时就没必要往下递归了,直接返回上层即可。

利用回溯法优化刚刚的算法

    void NQueen(int index)
    {
        if(index==n+1)
        {
            count++;
            return;
        }
        
        int x,i;
        for(x=1;x<=n;x++)
        {
            if(StatusTable[x]==false)//如果第x行没有皇后
            {
                bool flag=true; //flag为true表示在index位放入皇后无冲突,为false表示有冲突
                for(i=1;i<index;i++)//遍历之前的皇后
               {
    //                if(abs(x-i)==abs(QueenList[x]-QueenList[i]))    此时x还未放入index位 ,所以不能这么写
                    if(abs(index-i)==abs(x-QueenList[i]))//如果在index为放入x与之前某个皇后冲突 ,直接跳出循环,进入下一次外循环,将下一个x测试
                          {
                              flag=false;
                            break;
                        }
                }
                if(flag==true)
                {
                    QueenList[index]=x;
                    StatusTable[x]=true;
                        NQueen(index+1);
                    StatusTable[x]=false;
                }
            }
        }
    }
---------------------
作者:ptcshus
来源:CSDN
原文:https://blog.csdn.net/qq_41706331/article/details/86522325
版权声明:本文为博主原创文章,转载请附上博文链接!

posted @ 2019-07-18 21:28  天涯海角路  阅读(247)  评论(0)    收藏  举报