算法系列---回溯算法

引言

      寻找问题的解的一种可靠的方法是首先列出所有候选解,然后依次检查每一个,在检查完所有或部分候选解后,即可找到所需要的解。理论上,当候选解数量有限并且通过检查所有或部分候选解能够得到所需解时,上述方法是可行的。不过,在实际应用中,很少使用这种方法,因为候选解的数量通常都非常大(比如指数级,甚至是大数阶乘),即便采用最快的计算机也只能解决规模很小的问题。对候选解进行系统检查的方法有多种,其中回溯和分枝定界法是比较常用的两种方法。按照这两种方法对候选解进行系统检查通常会使问题的求解时间大大减少(无论对于最坏情形还是对于一般情形)。事实上,这些方法可以使我们避免对很大的候选解集合进行检查,同时能够保证算法运行结束时可以找到所需要的解。因此,这些方法通常能够用来求解规模很大的问题。

算法思想
      回溯(backtracking)是一种系统地搜索问题解答的方法。为了实现回溯,首先需要为问题定义一个解空间(solution space),这个空间必须至少包含问题的一个解(可能是最优的)。

     下一步是组织解空间以便它能被容易地搜索。典型的组织方法是图(迷宫问题)或树(N皇后问题)。
      一旦定义了解空间的组织方法,这个空间即可按深度优先的方法从开始节点进行搜索。

回溯方法的步骤如下:
     1) 定义一个解空间,它包含问题的解。
     2) 用适于搜索的方式组织该空间。
     3) 用深度优先法搜索该空间,利用限界函数避免移动到不可能产生解的子空间。
回溯算法的一个有趣的特性是在搜索执行的同时产生解空间。在搜索期间的任何时刻,仅保留从开始节点到当前节点的路径。因此,回溯算法的空间需求为O(从开始节点起最长路径的长度)。这个特性非常重要,因为解空间的大小通常是最长路径长度的指数或阶乘。所以如果要存储全部解空间的话,再多的空间也不够用。

算法应用
回溯算法的求解过程实质上是一个先序遍历一棵”状态树”的过程,只是这棵树不是遍历前预先建立的,而是隐含在遍历过程中<<数据结构>>(严蔚敏).
(1) 幂集问题(组合问题) (参见《数据结构》(严蔚敏))
     求含N个元素的集合的幂集。
     如对于集合A={1,2,3},则A的幂集为
     p(A)={{1,2,3},{1,2},{1,3},{1},{2,3},{2},{3},Φ}
幂集的每个元素是一个集合,它或是空集,或含集合A中的一个元素,或含A中的两个元素,或者等于集合A。反之,集合A中的每一个元素,它只有两种状态:属于幂集的元素集,或不属于幂集元素集。则求幂集P(A)的元素的过程可看成是依次对集合A中元素进行“取”或“舍”的过程,并且可以用一棵状态树来表示。求幂集元素的过程即为先序遍历这棵状态树的过程。
《算法系列---回溯算法》
下面给出程序:

《算法系列---回溯算法》 #include  < stdio.h >
《算法系列---回溯算法》#include 
< malloc.h >
《算法系列---回溯算法》
#define  ERROR 0
《算法系列---回溯算法》
#define  OK 1
《算法系列---回溯算法》
《算法系列---回溯算法》typedef 
int  ElemType;
《算法系列---回溯算法》typedef 
struct  LNode
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    ElemType data;
《算法系列---回溯算法》    
struct LNode *next;
《算法系列---回溯算法》}
 LNode, * LinkList;
《算法系列---回溯算法》
《算法系列---回溯算法》
// 初始化
《算法系列---回溯算法》
LinkList ListInit()
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》
《算法系列---回溯算法》    LNode 
*base=(LinkList)malloc(sizeof(LNode));
《算法系列---回溯算法》    
base->data=0;
《算法系列---回溯算法》    
base->next=NULL;
《算法系列---回溯算法》    
return base;
《算法系列---回溯算法》}

《算法系列---回溯算法》
// 插入一个元素
《算法系列---回溯算法》
int  ListInsert(LinkList L, int  i,ElemType e)
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    LNode 
*p,*s;
《算法系列---回溯算法》    
int j=0;
《算法系列---回溯算法》    p
=(LNode *)L;
《算法系列---回溯算法》    
while(p&&j<i1)
《算法系列---回溯算法》《算法系列---回溯算法》    
《算法系列---回溯算法》{
《算法系列---回溯算法》        p
=p->next;
《算法系列---回溯算法》        
++j;
《算法系列---回溯算法》    }

《算法系列---回溯算法》    
if(!p||j>i1)
《算法系列---回溯算法》        
return ERROR;
《算法系列---回溯算法》    s
=(LNode *)malloc(sizeof(LNode));
《算法系列---回溯算法》    s
->data=e;
《算法系列---回溯算法》    s
->next=p->next;
《算法系列---回溯算法》    p
->next=s;
《算法系列---回溯算法》    
return OK;
《算法系列---回溯算法》}

《算法系列---回溯算法》
// 删除一个结点
《算法系列---回溯算法》
int  ListDelete(LinkList  & L, int  i,ElemType  & e)
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    LinkList p
=L,q;
《算法系列---回溯算法》    
int j=0;
《算法系列---回溯算法》    
while(p->next&&j<i1)
《算法系列---回溯算法》《算法系列---回溯算法》    
《算法系列---回溯算法》{
《算法系列---回溯算法》        p
=p->next;
《算法系列---回溯算法》        
++j;
《算法系列---回溯算法》    }

《算法系列---回溯算法》    
if(!(p->next)||j>i1)
《算法系列---回溯算法》        
return ERROR;
《算法系列---回溯算法》    q
=p->next;
《算法系列---回溯算法》    p
->next=q->next;
《算法系列---回溯算法》    e
=q->data;
《算法系列---回溯算法》    free(q);
《算法系列---回溯算法》}

《算法系列---回溯算法》
// 长度
《算法系列---回溯算法》
int  ListLength(LinkList L)
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    LinkList p
=L;
《算法系列---回溯算法》    
int j=0;
《算法系列---回溯算法》    
if(!L)
《算法系列---回溯算法》        
return ERROR;
《算法系列---回溯算法》    
while(p->next)
《算法系列---回溯算法》《算法系列---回溯算法》    
《算法系列---回溯算法》{
《算法系列---回溯算法》        p
=p->next;
《算法系列---回溯算法》        
++j;
《算法系列---回溯算法》    }

《算法系列---回溯算法》    
return j;
《算法系列---回溯算法》}

《算法系列---回溯算法》
// 查找一个元素
《算法系列---回溯算法》
int  GetElem(LinkList L, int  i,ElemType  & e)
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    LNode 
*p=L;
《算法系列---回溯算法》    
int j=0;
《算法系列---回溯算法》    
while(p->next&&j<i)
《算法系列---回溯算法》《算法系列---回溯算法》    
《算法系列---回溯算法》{
《算法系列---回溯算法》        p
=p->next;
《算法系列---回溯算法》        
++j;
《算法系列---回溯算法》    }

《算法系列---回溯算法》    
if(!p||j>i)
《算法系列---回溯算法》        
return ERROR;
《算法系列---回溯算法》    e
=p->data;
《算法系列---回溯算法》    
return OK;
《算法系列---回溯算法》}

《算法系列---回溯算法》
// 输出链表元素
《算法系列---回溯算法》
void  Display(LinkList L)
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    LNode 
*p=L;
《算法系列---回溯算法》    
if(!(p->next))
《算法系列---回溯算法》《算法系列---回溯算法》    
《算法系列---回溯算法》{
《算法系列---回溯算法》        printf(
NULL,);
《算法系列---回溯算法》        
return;
《算法系列---回溯算法》    }

《算法系列---回溯算法》    
else
《算法系列---回溯算法》        p
=p->next;
《算法系列---回溯算法》    
while(p)
《算法系列---回溯算法》《算法系列---回溯算法》    
《算法系列---回溯算法》{
《算法系列---回溯算法》
《算法系列---回溯算法》        printf(
%d,,p->data);
《算法系列---回溯算法》        p
=p->next;    
《算法系列---回溯算法》    }

《算法系列---回溯算法》}

《算法系列---回溯算法》
// 求幂集
《算法系列---回溯算法》
void  PowerSet( int  i,LinkList A,LinkList  & B)
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    
int k=0;
《算法系列---回溯算法》    ElemType e
=0;
《算法系列---回溯算法》    
if(i>ListLength(A))
《算法系列---回溯算法》《算法系列---回溯算法》    
《算法系列---回溯算法》{
《算法系列---回溯算法》        Display(B);
《算法系列---回溯算法》        printf(
\n);
《算法系列---回溯算法》    }

《算法系列---回溯算法》    
else
《算法系列---回溯算法》《算法系列---回溯算法》    
《算法系列---回溯算法》{
《算法系列---回溯算法》        GetElem(A,i,e);
《算法系列---回溯算法》        k
=ListLength(B);
《算法系列---回溯算法》        ListInsert(B,k
+1,e);
《算法系列---回溯算法》        PowerSet(i
+1,A,B);
《算法系列---回溯算法》
《算法系列---回溯算法》        ListDelete(B,k
+1,e);
《算法系列---回溯算法》        PowerSet(i
+1,A,B);
《算法系列---回溯算法》    }

《算法系列---回溯算法》}

《算法系列---回溯算法》
《算法系列---回溯算法》
int  main()
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    LinkList list
=ListInit(); //初始化
《算法系列---回溯算法》
    LinkList list2=ListInit();//初始化
《算法系列---回溯算法》

《算法系列---回溯算法》    ListInsert(list,
1,1);//插入元素
《算法系列---回溯算法》
    ListInsert(list,2,2);
《算法系列---回溯算法》    ListInsert(list,
3,3);
《算法系列---回溯算法》
《算法系列---回溯算法》    Display(list);
//输出元素
《算法系列---回溯算法》
    printf(\npower set is:\n);
《算法系列---回溯算法》    PowerSet(
1,list,list2);//求幂集
《算法系列---回溯算法》
}

 

(2)迷宫问题(参见《数据结构》(严蔚敏))
计算机解迷宫时,通常用的是”试探和回溯”的方法,即从入口出发,顺某一方向向前探索,若能走通,则继续往前走;否则沿原路退回,换一个方向再继续探索,直至所有可能的通路都探索到为止,如果所有可能的通路都试探过,还是不能走到终点,那就说明该迷宫不存在从起点到终点的通道。

  1.从入口进入迷宫之后,不管在迷宫的哪一个位置上,都是先往东走,如果走得通就继续往东走,如果在某个位置上往东走不通的话,就依次试探往南、往西和往北方向,从一个走得通的方向继续往前直到出口为止;

  2.如果在某个位置上四个方向都走不通的话,就退回到前一个位置,换一个方向再试,如果这个位置已经没有方向可试了就再退一步,如果所有已经走过的位置的四个方向都试探过了,一直退到起始点都没有走通,那就说明这个迷宫根本不通;
  
   3.所谓”走不通”不单是指遇到”墙挡路”,还有”已经走过的路不能重复走第二次”,它包括”曾经走过而没有走通的路”。显然为了保证在任何位置上都能沿原路退回,需要用一个”后进先出”的结构即栈来保存从入口到当前位置的路径。并且在走出出口之后,栈中保存的正是一条从入口到出口的路径。

由此,求迷宫中一条路径的算法的基本思想是:
若当前位置”可通”,则纳入”当前路径”,并继续朝”下一位置”探索;若当前位置”不可通”,则应顺着”来的方向”退回到”前一通道块”,然后朝着除”来向”之外的其他方向继续探索;若该通道块的四周四个方块均”不可通”,则应从”当前路径”上删除该通道块。

设定当前位置的初值为入口位置;
  do{
    若当前位置可通,
    则{
     将当前位置插入栈顶;       // 纳入路径
     若该位置是出口位置,则算法结束;
      // 此时栈中存放的是一条从入口位置到出口位置的路径
     否则切换当前位置的东邻方块为新的当前位置;
     }
    否则
    {
    若栈不空且栈顶位置尚有其他方向未被探索,
    则设定新的当前位置为: 沿顺时针方向旋转找到的栈顶位置的下一相邻块;
    若栈不空但栈顶位置的四周均不可通,
    则{ 删去栈顶位置;         // 从路径中删去该通道块
      若栈不空,则重新测试新的栈顶位置,
      直至找到一个可通的相邻块或出栈至栈空;
     }
   }
} while (栈不空);

程序如下:

 

《算法系列---回溯算法》 #include  < stdio.h >
《算法系列---回溯算法》
《算法系列---回溯算法》
#define  WALL   0   //
《算法系列---回溯算法》
#define  CORRIDOR 1  // 通道
《算法系列---回溯算法》
#define  PATH  9  // 为路径上的一块
《算法系列---回溯算法》
#define  TRIED 2  //
《算法系列---回溯算法》
《算法系列---回溯算法》
#define  ROW_NUM    7  // 迷宫数组行数
《算法系列---回溯算法》
#define  COL_NUM   13  // 列数
《算法系列---回溯算法》
《算法系列---回溯算法》
#define  TRUE 1
《算法系列---回溯算法》
#define  FALSE 0
《算法系列---回溯算法》
#define  MAXSIZE 50
《算法系列---回溯算法》typedef 
struct  
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    
int row;
《算法系列---回溯算法》    
int col;
《算法系列---回溯算法》}
PosType;
《算法系列---回溯算法》
《算法系列---回溯算法》typedef 
struct  
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    
int ord;      //通道块在路径上的”序号”
《算法系列---回溯算法》
    PosType seat; //通道块在迷宫中的坐标
《算法系列---回溯算法》
    int di;       //当前通道块的方向
《算法系列---回溯算法》
}
SElemType;
《算法系列---回溯算法》typedef 
struct  
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    SElemType S[MAXSIZE];
《算法系列---回溯算法》    
int top;
《算法系列---回溯算法》}
MazeType;
《算法系列---回溯算法》
// 迷宫
《算法系列---回溯算法》《算法系列---回溯算法》
int  grid[ROW_NUM][COL_NUM] = 《算法系列---回溯算法》 {《算法系列---回溯算法》{1110111001111},
《算法系列---回溯算法》《算法系列---回溯算法》                            
《算法系列---回溯算法》{1011101111101},
《算法系列---回溯算法》《算法系列---回溯算法》                            
《算法系列---回溯算法》{1000001010101},
《算法系列---回溯算法》《算法系列---回溯算法》                            
《算法系列---回溯算法》{1000111010111},
《算法系列---回溯算法》《算法系列---回溯算法》                            
《算法系列---回溯算法》{1111100001000},
《算法系列---回溯算法》《算法系列---回溯算法》                            
《算法系列---回溯算法》{0000100000000},
《算法系列---回溯算法》《算法系列---回溯算法》                            
《算法系列---回溯算法》{0000111111111}}
;
《算法系列---回溯算法》
// 当前位置是否可以通过
《算法系列---回溯算法》
bool  Valid(PosType pos)
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    
if(pos.row>=0&&pos.row<=ROW_NUM&&pos.col>=0&&pos.col<=COL_NUM&&grid[pos.row][pos.col]==CORRIDOR)
《算法系列---回溯算法》        
return TRUE;
《算法系列---回溯算法》    
else
《算法系列---回溯算法》        
return FALSE;
《算法系列---回溯算法》}

《算法系列---回溯算法》
void  FootPrint(PosType pos) // 留下足迹
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    grid[pos.row][pos.col]
=PATH;
《算法系列---回溯算法》}

《算法系列---回溯算法》
void  Undo(PosType pos)  // 留下不能通过的标识
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    grid[pos.row][pos.col]
=TRIED;
《算法系列---回溯算法》}

《算法系列---回溯算法》
// 当前位置的下一个位置
《算法系列---回溯算法》
PosType NextPos(PosType cur, int  di)
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    PosType next;
《算法系列---回溯算法》    
switch(di)
《算法系列---回溯算法》《算法系列---回溯算法》    
《算法系列---回溯算法》{
《算法系列---回溯算法》    
case 0//
《算法系列---回溯算法》
        next.row=cur.row;
《算法系列---回溯算法》        next.col
=cur.col+1;
《算法系列---回溯算法》        
break;
《算法系列---回溯算法》    
case 1//
《算法系列---回溯算法》
        next.row=cur.row+1;
《算法系列---回溯算法》        next.col
=cur.col;
《算法系列---回溯算法》        
break;
《算法系列---回溯算法》    
case 2:  //西
《算法系列---回溯算法》
        next.row=cur.row;
《算法系列---回溯算法》        next.col
=cur.col1;
《算法系列---回溯算法》        
break;
《算法系列---回溯算法》    
case 3:  //
《算法系列---回溯算法》
        next.row=cur.row1;
《算法系列---回溯算法》        next.col
=cur.col;
《算法系列---回溯算法》        
break;
《算法系列---回溯算法》    }

《算法系列---回溯算法》    
return next;
《算法系列---回溯算法》}

《算法系列---回溯算法》
// 是否到达终点
《算法系列---回溯算法》
bool  Done(PosType cur,PosType end)
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    
if(cur.row==end.row&&cur.col==end.col)
《算法系列---回溯算法》        
return TRUE;
《算法系列---回溯算法》    
else
《算法系列---回溯算法》        
return FALSE;
《算法系列---回溯算法》}

《算法系列---回溯算法》
// 寻找迷宫路径
《算法系列---回溯算法》
bool  MazePath(MazeType  & path,PosType start,PosType end)
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    SElemType e;
《算法系列---回溯算法》    path.top
=-1;
《算法系列---回溯算法》    
int step=1;
《算法系列---回溯算法》    PosType curpos
=start;
《算法系列---回溯算法》    
do
《算法系列---回溯算法》《算法系列---回溯算法》    
《算法系列---回溯算法》{
《算法系列---回溯算法》        
if(Valid(curpos))
《算法系列---回溯算法》《算法系列---回溯算法》        
《算法系列---回溯算法》{
《算法系列---回溯算法》            FootPrint(curpos);
《算法系列---回溯算法》            e.ord
=step;
《算法系列---回溯算法》            e.di
=0;
《算法系列---回溯算法》            e.seat
=curpos;
《算法系列---回溯算法》            path.S[
++path.top]=e;
《算法系列---回溯算法》            
if(Done(curpos,end))
《算法系列---回溯算法》                
return TRUE;
《算法系列---回溯算法》            curpos
=NextPos(curpos,0);
《算法系列---回溯算法》            step
++;
《算法系列---回溯算法》        }

《算法系列---回溯算法》        
else
《算法系列---回溯算法》《算法系列---回溯算法》        
《算法系列---回溯算法》{
《算法系列---回溯算法》            
if(path.top>-1)//棧不空
《算法系列---回溯算法》《算法系列---回溯算法》
            《算法系列---回溯算法》{
《算法系列---回溯算法》                e
=path.S[path.top];
《算法系列---回溯算法》                
while(e.di==3&&path.top>-1)
《算法系列---回溯算法》《算法系列---回溯算法》                
《算法系列---回溯算法》{
《算法系列---回溯算法》                    Undo(e.seat);
《算法系列---回溯算法》                    e
=path.S[path.top];
《算法系列---回溯算法》                }

《算法系列---回溯算法》                
if(e.di<3)
《算法系列---回溯算法》《算法系列---回溯算法》                
《算法系列---回溯算法》{
《算法系列---回溯算法》                    e.di
++;
《算法系列---回溯算法》                    path.S[
++path.top]=e;
《算法系列---回溯算法》                    curpos
=NextPos(e.seat,e.di);
《算法系列---回溯算法》                }

《算法系列---回溯算法》            }
//if
《算法系列---回溯算法》
        }
//else
《算法系列---回溯算法》
    }
while(path.top>-1);
《算法系列---回溯算法》    
return FALSE;
《算法系列---回溯算法》}

《算法系列---回溯算法》
// 输出路径
《算法系列---回溯算法》
void  PrintPath(MazeType path)
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    
int i=0;
《算法系列---回溯算法》    
while(i<=path.top)
《算法系列---回溯算法》《算法系列---回溯算法》    
《算法系列---回溯算法》{
《算法系列---回溯算法》        printf(
第%d步:(%d,%d)\n,path.S[i].ord,path.S[i].seat.row,path.S[i].seat.col);
《算法系列---回溯算法》        i
++;
《算法系列---回溯算法》    }

《算法系列---回溯算法》}

《算法系列---回溯算法》
// 输出路径
《算法系列---回溯算法》
void  PrintPath2()
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    
for(int i=0;i<ROW_NUM;i++)
《算法系列---回溯算法》        
for(int j=0;j<COL_NUM;j++)
《算法系列---回溯算法》        
if(grid[i][j]==PATH)
《算法系列---回溯算法》            printf(
(%d,%d)\n,i,j);
《算法系列---回溯算法》}

《算法系列---回溯算法》
int  main()
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    MazeType path;
《算法系列---回溯算法》《算法系列---回溯算法》    PosType start
=《算法系列---回溯算法》{0,0},end=《算法系列---回溯算法》{6,12};
《算法系列---回溯算法》    
if(MazePath(path,start,end))
《算法系列---回溯算法》        PrintPath(path);
《算法系列---回溯算法》    
else
《算法系列---回溯算法》        printf(
not reachable!\n);
《算法系列---回溯算法》
《算法系列---回溯算法》    PrintPath2();
《算法系列---回溯算法》}

(3)N皇后问题:
在一个N*N的棋盘上放置N个皇后,且使得每两个之间不能互相攻击,也就是使得每两个不在同一行,同一列和同一斜角线上。
对于N=1,问题的解很简单,而且我们很容易看出对于N=2和N=3来说,这个问题是无解的。所让我们考虑4皇后问题并用回溯法对它求解。因为每个皇后都必须分别占据—行,我们需要做的不过是为图1棋盘上的每个皇后分配一列。

 《算法系列---回溯算法》
     我们从空棋盘开始,然后把皇后1放到它所在行的第一个可能位置上,也就是第一行第—列。对于皇后2,在经过第一列和第二列的失败尝试之后,我们把它放在第一个可能的位置,就是格子〔23),位于第二行第二列的格子。这被证明是一个死胡同,因为皇后:将没有位置可放。所以,该算法进行回溯,把皇后2放在下一个可能位置(24)上。然后皇后3就可以放在(32),这被证明是另一个死胡同。该算法然后就回溯到底,把皇后1移到(12)。接着皇后2(24),皇后3(31),而皇后4(43),这就是该问题的一个解。图2给出了这个查找的状态空间树。
《算法系列---回溯算法》
 程序如下:

 

《算法系列---回溯算法》 #include  < stdio.h >
《算法系列---回溯算法》#include 
< math.h >
《算法系列---回溯算法》
#define  N  4
《算法系列---回溯算法》
int  col[N + 1 ];
《算法系列---回溯算法》
// 输出结果
《算法系列---回溯算法》
void  Output()
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    
for(int i=1;i<=N;i++)
《算法系列---回溯算法》《算法系列---回溯算法》    
《算法系列---回溯算法》{
《算法系列---回溯算法》        printf(
(%d,%d)\n,i,col[i]);
《算法系列---回溯算法》    }

《算法系列---回溯算法》    printf(
\n);
《算法系列---回溯算法》}

《算法系列---回溯算法》
// 求解函数
《算法系列---回溯算法》
void  Queen( int  i, int  n)
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    
if(i>n)
《算法系列---回溯算法》        Output();
《算法系列---回溯算法》    
else
《算法系列---回溯算法》《算法系列---回溯算法》    
《算法系列---回溯算法》{
《算法系列---回溯算法》        
for(int j=1;j<=n;++j)
《算法系列---回溯算法》《算法系列---回溯算法》        
《算法系列---回溯算法》{
《算法系列---回溯算法》            
int k=1;
《算法系列---回溯算法》            col[i]
=j;
《算法系列---回溯算法》            
while(k<i)
《算法系列---回溯算法》《算法系列---回溯算法》            
《算法系列---回溯算法》{
《算法系列---回溯算法》                
if((col[k]col[i])*(fabs(col[k]col[i])fabs(ki))!=0)
《算法系列---回溯算法》《算法系列---回溯算法》                
《算法系列---回溯算法》{
《算法系列---回溯算法》                    k
++;
《算法系列---回溯算法》                    
if(k==i)
《算法系列---回溯算法》                        Queen(i
+1,n);
《算法系列---回溯算法》                }

《算法系列---回溯算法》                
else
《算法系列---回溯算法》《算法系列---回溯算法》                
《算法系列---回溯算法》{
《算法系列---回溯算法》                    
break;
《算法系列---回溯算法》                }

《算法系列---回溯算法》            }

《算法系列---回溯算法》        }

《算法系列---回溯算法》    }

《算法系列---回溯算法》}

《算法系列---回溯算法》
int  main()
《算法系列---回溯算法》《算法系列---回溯算法》
《算法系列---回溯算法》 {
《算法系列---回溯算法》    printf(
the answer is:\n);
《算法系列---回溯算法》    
for(int i=1;i<=N;i++)
《算法系列---回溯算法》《算法系列---回溯算法》    
《算法系列---回溯算法》{
《算法系列---回溯算法》        col[
1]=i; //设置第一行
《算法系列---回溯算法》
        Queen(2,N);
《算法系列---回溯算法》    }

《算法系列---回溯算法》}

结果如下:
《算法系列---回溯算法》
 

    原文作者:YY哥
    原文地址: https://www.cnblogs.com/hustcat/archive/2008/04/09/1144645.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞