N皇后问题

问题:国际象棋中的N皇后问题推广的来

算法思想:方法一:回溯法, 从一条路往前走,能进则进,不能进则退回来,换一条路再试。

                 方法二: 位运算来求解N皇后的高效算法(高效)

方法一:代码实现

#include<stdio.h>
#include<stdlib.h>
#define N 9
int num = 0;       //保存所有可能的结果数
int row[N] = {0};  //保存第i行的皇后所处的列
int queen(int i)
{
        int j,k;
        if(i==N)
        {
                num++;
                printf("=======================%d========================\n",num);
                for(j=0;j<N;j++)
                {
                        printf("%*d\n",(row[j])*2,row[j]);
                }
                return 0;
        }
        else
        {
                //第i行的皇后选择列
                for(j = 0;j<N;j++)
                {
                        //判断第i行皇后是否与前面的皇后冲突
                        for(k = 0;k<i;k++)
                        {
                                if(row[k]==j || abs(k-i)==abs(row[k]-j))
                                  break;
                        }
                        //没有冲突选项时选取下一行
                        if(k==i)
                        {
                                row[i] = j;
                                queen(i+1);
                        }
                }
        }
}
int main()
{
        queen(0);
        return 0;
}

方法二:参考:http://blog.csdn.net/hackbuteer1/article/details/6657109

    /* 
    ** 目前最快的N皇后递归解决方法 
    ** N Queens Problem 
    ** 试探-回溯算法,递归实现 
    */  
    #include "iostream"  
    using namespace std;  
    #include "time.h"  
      
    // sum用来记录皇后放置成功的不同布局数;upperlim用来标记所有列都已经放置好了皇后。  
    long sum = 0, upperlim = 1;       
      
    // 试探算法从最右边的列开始。  
    void test(long row, long ld, long rd)  
    {  
        if (row != upperlim)  
        {  
            // row,ld,rd进行“或”运算,求得所有可以放置皇后的列,对应位为0,  
            // 然后再取反后“与”上全1的数,来求得当前所有可以放置皇后的位置,对应列改为1  
            // 也就是求取当前哪些列可以放置皇后  
            long pos = upperlim & ~(row | ld | rd);   
            while (pos)    // 0 -- 皇后没有地方可放,回溯  
            {  
                // 拷贝pos最右边为1的bit,其余bit置0  
                // 也就是取得可以放皇后的最右边的列  
                long p = pos & -pos;                                                
      
                // 将pos最右边为1的bit清零  
                // 也就是为获取下一次的最右可用列使用做准备,  
                // 程序将来会回溯到这个位置继续试探  
                pos -= p;                             
      
                // row + p,将当前列置1,表示记录这次皇后放置的列。  
                // (ld + p) << 1,标记当前皇后左边相邻的列不允许下一个皇后放置。  
                // (ld + p) >> 1,标记当前皇后右边相邻的列不允许下一个皇后放置。  
                // 此处的移位操作实际上是记录对角线上的限制,只是因为问题都化归  
                // 到一行网格上来解决,所以表示为列的限制就可以了。显然,随着移位  
                // 在每次选择列之前进行,原来N×N网格中某个已放置的皇后针对其对角线  
                // 上产生的限制都被记录下来了  
                test(row + p, (ld + p) << 1, (rd + p) >> 1);                                
            }  
        }  
        else     
        {  
            // row的所有位都为1,即找到了一个成功的布局,回溯  
            sum++;  
        }  
    }  
      
    int main(int argc, char *argv[])  
    {  
        time_t tm;  
        int n = 16;  
      
        if (argc != 1)  
            n = atoi(argv[1]);  
        tm = time(0);  
      
        // 因为整型数的限制,最大只能32位,  
        // 如果想处理N大于32的皇后问题,需要  
        // 用bitset数据结构进行存储  
        if ((n < 1) || (n > 32))                   
        {  
            printf(" 只能计算1-32之间\n");  
            exit(-1);  
        }  
        printf("%d 皇后\n", n);  
      
        // N个皇后只需N位存储,N列中某列有皇后则对应bit置1。  
        upperlim = (upperlim << n) - 1;           
      
        test(0, 0, 0);  
        printf("共有%ld种排列, 计算时间%d秒 \n", sum, (int) (time(0) - tm));  
        system("pause");  
        return 0;  
    }  

 

转载于:https://my.oschina.net/u/3166429/blog/1341356

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值