回溯法特点分析以及经典N皇后问题

/*
以深度优先的方式系统地搜索问题的解的算法称为回溯法
它适用于解一些组合数较大的问题
*/
/*
在用回溯法搜索解空间树的时候,通常采用两种策略来避免无效搜索,提高回溯法的搜索效率
。其一是用约束函数在扩展结点处剪去不满足约束的子树,其二是用限界函数剪去不能得到最
优解的子树。这两类函数统称为剪枝函数。
运用回溯法的三个步骤:
(1)针对所给问题,定义问题的解空间
(2)确定易于搜索的解空间结构,子集树还是排列树
(3)以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索

当所给的问题是从n个元素的集合S中找出满足某种性质的子集时,
相应的解空间树称为子集树。这类子集树通常有2^n个叶结点,其结点总个数为
2^(n+1)-1。遍历子集树的任何算法均需要2^n计算时间。

当所给的问题是确定n个元素满足某种性质的排列时,相应的解空间树称为
排列树。排列树通常有n!个叶结点。因此遍历排列树需要n!的计算时间。
*/

/*
回溯法搜集子集树的一般算法可描述如下:
*/
void Backtrack( int t )
{
 if ( t > n )
 {
  Output( x );
 }
 else
 {
  for( int i = 0; i <= 1; ++i )
  {
   x[t] = i;
   if ( Constraint(t) && Bound(t) )
   {
    Backtrack(t+1);
   }
  }
 }
}

/*
用回溯法搜索排列树的算法框架如下:
*/
void Backtrack( int t )
{
 if ( t > n )
 {
  Output(x);
 }
 else
 {
  for( int i = t; i <= n; ++i )
  {
   Swap( x[t], x[i] );
   if ( Constraint(t) && Bound(t) )
   {
    Backtrack(t+1);
   }
   Swap(x[t],x[i]);
  }
 }
}

#include
using namespace std;
/*
解空空间是完全N叉树
x[i]表示第i个皇后放在第i行的第x[i]列
*/
class Queen
{
 friend int nQueen(int);
private:
 bool Place(int k);
 void Backtrack(int t);
 int n;
 //皇后个数
 int *x;
 //当前解
 long sum;
 //当前已经找到的可行方案数
};

bool Queen::Place(int k)
{
 for( int j = 1; j < k; ++j )
 {
  if ( ( abs( k - j ) == abs( x[j] - x[k] ) ) || ( x[j] == x[k] ) )
  {
   return false;
  }
 }
 return true;
}

void Queen::Backtrack(int t)
{
 if ( t > n )
 {
  sum++;
 }
 else
 {
  for( int i = 1; i <= n; ++i )
  //如果是全排列的则需要回溯时复原原来的值
  //完全N叉树确定值范围则不需要这样
  {
   x[t] = i;
   //将第t个元素放在i列
   if ( Place(t) )
   {
    Backtrack( t + 1 );
   }
  }
 }
}

int nQueen( int n )
{
 Queen X;
 //初始化X
 X.n = n;
 X.sum = 0;
 int *p = new int[n+1];
 for( int i = 0; i <= n; ++i )
 {
  p[i] = 0;
 }
 X.x = p;
 X.Backtrack(1);
 delete []p;
 return X.sum;
}

void Queen::Backtrack(void)
{
 x[1] = 0;
 int k = 1;
 while( k > 0 )
 {
  x[k] += 1;
  //选中第x[k]列
  while( ( x[k] <= n ) && !( Place(k) ) )
  {
   x[k] += 1;
  }
  if( x[k] <= n )
  {
   if ( k == n  )
   {
    sum++;
   }
   else
   {
    ++k;
    x[k] = 0;
   }
  }
  else
  {
   --k;
   //上一行的列继续调整
  }
 }
}
int main()
{
 return 0;
}

你可能感兴趣的:(回溯法特点分析以及经典N皇后问题)