zoukankan      html  css  js  c++  java
  • 回溯算法之n皇后问题

    今天在看深度优先算法的时候,联想到DFS本质不就是一个递归回溯算法问题,只不过它是应用在图论上的。OK,写下这篇博文也是为了回顾一下回溯算法设计吧。

    学习回溯算法问题,最为经典的问题我想应该就是八皇后问题了。

    一、适用范围

      回溯算法应用的范围当然是很多了,那么归纳一下:如果一个问题中,没有很好的数学模型来解决,或者有数学模型解决,但是很难实现,那么我们就可以使用回溯算法来求解。

    二、定义

    回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。

    用回溯算法解决问题的一般步骤:
    1 针对所给问题,定义问题的解空间,它至少包含问题的一个(最优)解。
    2 确定易于搜索的解空间结构,使得能用回溯法方便地搜索整个解空间 。
    3 以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索。
    问题的解空间通常是在搜索问题解的过程中动态产生的,这是回溯算法的一个重要特性。

    例题:八皇后问题

    在8*8国际象棋棋盘上,要求在每一行放置一个皇后,且能做到在竖方向,斜方向都没有冲突。国际象棋的棋盘如下图所示:

    3c3f32555ed870c1b745aeb2

    显然,每一行可以而且必须放一个皇后,所以n皇后问题的解可以用一个n元向量X=(x1,x2,.....xn)表示,其中,1≤ i≤ n且1≤ xi≤ n,即第n个皇后放在第i行第xi列上。

    由于两个皇后不能放在同一列上,所以,解向量X必须满足的约束条件为:xi≠ xj;

    若两个皇后的摆放位置分别是(i,xi)和(j,xj),在棋盘上斜率为-1的斜线上,满足条件i-j=xi-xj;在棋盘上斜率为1的斜线上,满足条件i+j=xi+xj;

    综合两种情况,由于两个皇后不能位于同一斜线上,所以,解向量X必须满足的约束条件为:
    |i-xi|≠ |j-xj|

     1 #include <cmath>
     2 #include <cstdlib>
     3 #include <iostream>
     4 using namespace std;
     5 const int MAXSIZE=100;
     6 
     7 int Pos_Queen[MAXSIZE];//Pos_Queen[k]代表的含义是第k行的皇后应放在第Pos_Queen[k]列处
     8 int count=0;//全局变量,用来记录所有可能性数量
     9 bool Is_Safe(int k)//考察皇后k放置在Pos_Queen[k]列是否安全
    10 {
    11     for(int i=1; i<k; i++)
    12         if( Pos_Queen[k] == Pos_Queen[i] || abs(k-i) == abs(Pos_Queen[k]-Pos_Queen[i]) )
    13             return false;
    14     return true;
    15 }
    16 
    17 //打印皇后摆放情况
    18 void Print_Queen( int queenList[], int n )
    19 {
    20     cout<<"Case "<<(++count)<<":"<<endl;
    21     cout<<"  ";
    22     for( int i=1; i<=n; i++ )
    23     {
    24         cout<<i<<" ";
    25     }
    26     cout<<endl;
    27     for( int i=1; i<=n; i++ )
    28     {
    29         cout<<i<<" ";
    30         for( int j=1; j<queenList[i]; j++ )
    31         {
    32             cout<<"* ";
    33         }
    34         cout<<"Q ";
    35         for( int j=1; j<( n - queenList[i]+1 ); j++ )
    36         {
    37             cout<<"* ";
    38         }
    39         cout<<endl;
    40     }
    41     cout<<endl;
    42 }
    43 
    44 void queue(int n)
    45 {
    46     int i,k;
    47     for(i=1; i<=n; i++)
    48         Pos_Queen[i]=0;
    49     k=1;
    50     while( k>=1 )
    51     {
    52         Pos_Queen[k] = Pos_Queen[k]+1;   //在下一列放置第k个皇后
    53         while( Pos_Queen[k] <= n && !Is_Safe(k) )
    54             Pos_Queen[k] = Pos_Queen[k]+1;//搜索下一列
    55         if( Pos_Queen[k] <= n && k == n )//得到一个输出
    56         {
    57             count++;
    58             //Print_Queen(Pos_Queen,n);
    59             //return;//若return则只求出其中一种解,若不return则可以继续回溯,求出全部的可能的解
    60         }
    61         else if( Pos_Queen[k] <= n && k < n )
    62             k = k+1;//放置下一个皇后
    63         else
    64         {
    65             Pos_Queen[k]=0;//重置Pos_Queen[k],回溯
    66             k = k-1;
    67         }
    68     }
    69 }
    70 
    71 int main()
    72 {
    73     int n;
    74     cout<<"输入皇后个数n:";
    75     cin>>n;
    76     queue(n);
    77     cout<<n<<"皇后问题共有"<<count<<"种放法"<<endl;
    78     return 0;
    79 }

    学习心得:

    1.在编写递归枚举程序之前,需要深入分析问题,对模型精雕细琢。一般还应对解答树的结点数有一个粗略的估计,作为评价模型的重要依据。

    2.如果在回溯法中试用了辅助的全局变量,则一定要及时把它们恢复原状。例如,若函数有多个出口,则需要在每个出口处恢复被修改的值。

    3.从解答树的角度讲,回溯法正是按照深度优先的顺序在遍历解答树。

  • 相关阅读:
    什么是网络爬虫?为什么要选择Python写网络爬虫?
    Python爬取全书网小说,免费看小说
    Python爬取CFDA化妆品生产信息
    Python爬取新浪微博评论
    想入门Python爬虫?三步到位,轻松入门
    Python基础知识点:类型和运算
    Python数据分析丨numpy基本操作,了解一下?
    在这个520特别的日子里,分享几个用的上的Python代码
    Python书单推荐一波【内含PDF下载地址】
    Python仿手机游戏开发贪吃蛇大作战
  • 原文地址:https://www.cnblogs.com/HXloveLL/p/3687230.html
Copyright © 2011-2022 走看看