n皇后问题

递归算法

bool valid(vector<int> &res, int r)
    {  
        int nCol = res.size();
        for(int i=0;i<nCol;i++){  
            if(res[i]==r || abs(res[i]-r)==nCol-i){  
                return false;  
            }  
        }
        return true;  
    } 

    void queen(int n, int l, vector<int> res, int &nCount)
    {
        if (l == n)
        {
            nCount++;
            return;
        }
        for (int i=0; i<n; i++)
        {
            if (!valid(res, i))
                continue;
    
            res.push_back(i);
            queen(n, l+1, res, nCount);
            res.pop_back();
        }
    }
    int totalNQueens(int n) {
        vector<int> vec;
        int nCount = 0;
        queen(n, 0, vec, nCount);
        return nCount;
    }

非递归算法:

int place(vector<int> &x, int k)
{
  int j;
  
  for (j = 0; j < k; j++)
  {
    if ((abs(k - j) == abs(x[j] - x[k])) || (x[j] == x[k]))
      return 0;
  }
  return 1;
}

int totalNQueens1(int n) {
    vector<int> x(n);
    int nCount = 0;
    
    for (int i = 0; i < n; i ++)
    {
        x[i] = 0;
    }

    x[0] = -1;
    int k = 0;
    while (k >= 0)
    {
        x[k] += 1;
        while ((x[k] < n) && !(place(x, k)))
            x[k] += 1;
        if (x[k] < n)
        {
            if (k == n - 1)
                nCount++;
            else
            {
                k++;
                x[k] = -1;
            }
        }
        else
            k--;
    }

    return nCount;
}

最高效的算法

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

long sum = 0, upperlim = 1;

void test(long row, long ld, long rd) \\row表示已经有皇后的行,ld、rd分别表示已经有皇后的斜列,每一位表示该列中可以摆放皇后的位置,1表示可以摆放,0表示不可以摆放。row在每查找下一列时不用改动,ld、rd需要分别左移和右移一位。
{

   if (row != upperlim) \\当所有行都有皇后时说明摆放完毕
   {
  long pos = upperlim & ~(row | ld | rd); \\pos的每一位表示该列中可以摆放皇后的位置,1表示可以摆放,0表示不可以摆放
  while (pos) \\如果pos中还有可以摆放的位置
  {
 long p = pos & -pos; \\p为pos中最末一个可以摆放的位置

 pos -= p; \\将p从可摆放位置去掉
 test(row + p, (ld + p) << 1, (rd + p) >> 1); \\对下一列进行判断
  }
   } else
  sum++;
}

int main(int argc, char *argv[])
{
   time_t tm;
   int n = 16;

   if (argc != 1)
  n = atoi(argv[1]);
   tm = time(0);
   if ((n < 1) || (n > 32))
   {
  printf(" 只能计算1-32之间\n");
  exit(-1);
   }
   printf("%d 皇后\n", n);
   upperlim = (upperlim << n) - 1;

   test(0, 0, 0);
   printf("共有%ld种排列, 计算时间%d秒 \n", sum, (int) (time(0) - tm));
}

 

posted @ 2014-09-06 22:27  山是水的故事  阅读(141)  评论(0编辑  收藏  举报