分支限界法求解迷宫问题

分支限界法

定义

分支限界法类似与回溯法,也是一种在问题的解空间树上搜索问题的解法。但后者的目标是找到满足约束条件的所有解,而前者要求找到某种意义下的最优解(极大值、极小值)。
分支限界法采用广度优先的策略,依次搜索活结点的所有分支,也就是所有相邻结点。

设计思想

  1. 设计合适的限界函数,排除该活结点不可能产生最优解的孩子结点,来提高搜索效率。
  2. 组织活结点表,可采用队列式分枝限界法和优先队列式分枝限界法。
    (1)队列式:
    a.将根结点加入活结点队列
    b.从活结点队中取出队头结点,作为当前扩展结点
    c.对当前扩展结点,从左到右的产生它的所有孩子结点,用约束条件检查,把所有满足约束条件的孩子结点加入活结点队列
    d.重复步骤b和c,直到找到一个解或活结点队列为空为止
    (2)优先队列式:
    与(1)相似,每次先计算起始结点的优先级再将它加入优先队列
  3. 确定最优解的解向量
    方法一:对每个扩展节点保存从根节点到该结点的路径
    方法二:在搜索过程中构建搜所经过的树结构,利用双亲结点指针来实现对该树结构的保存

题目介绍

题目内容

定义一个二维数组,例如:

int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 0, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

输入格式:
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一最短路径。

输出格式:
左上角到右下角的最短路径,格式如样例所示。

输入样例:

0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0

输出样例:

(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)

解题思路

  1. 构建dot结构体用来存放每个点的信息,包括该点当前标号n(取值为0~24),当前点的值num(0或1),当前路径已经有的点数count(包含本点)以及用来存储当前路径经历的点的标号的数组temp。
  2. 构建dot结构体的队列queue,完成对初始化队列函数initQueue()、进队函数Push()和出队函数Pop()的编写。
  3. 编写getAns函数用来获得答案,答案存储在全局变量ans[25]和minnum中,其中ans[25]中存储了结果路径经历的点的值,minnum存储了最终得到路径上点的个数。

解题代码

getAns(queue *q,dot d[],int pos){
    int i=0;
    if(pos==24)//已到达终点(4,4)
     if(d[pos].countminnum)
       return;//若已大于最小点数但还未到终点,剪枝
    if(pos%5!=4&&d[pos+1].num!=1){//不在右边界
       Push(q,d[pos+1]);
       d[pos+1].count=d[pos].count+1;
       for(i=0;i<25;i++)
          d[pos+1].temp[i]=d[pos].temp[i];
       d[pos+1].temp[d[pos+1].count]=pos+1;
       getAns(q,d,pos+1);
    }
    if(pos/5!=4&&d[pos+5].num!=1){//不在下边界
       Push(q,d[pos+5]);
       d[pos+5].count=d[pos].count+1;
       for(i=0;i<25;i++)
          d[pos+5].temp[i]=d[pos].temp[i];
       d[pos+5].temp[d[pos+5].count]=pos+5;
       getAns(q,d,pos+5);
    }
    if(pos/5!=0&&d[pos-5].num!=1){//不在上边界
       Push(q,d[pos-5]);
       d[pos-5].count=d[pos].count+1;
       for(i=0;i<25;i++)
          d[pos-5].temp[i]=d[pos].temp[i];
       d[pos-5].temp[d[pos-5].count]=pos-5;
       getAns(q,d,pos-5);
    }
    if(pos%5!=0&&d[pos-1].num!=1){//不在左边界
       Push(q,d[pos-1]);
       d[pos-1].count=d[pos].count+1;
       for(i=0;i<25;i++)
          d[pos-1].temp[i]=d[pos].temp[i];
       d[pos-1].temp[d[pos-1].count]=pos-1;
       getAns(q,d,pos-1);
    }
}

总结

分支限界法按广度优先策略搜索问题的解空间树,在搜索过程中,对待处理的结点根据限界函数估算目标函数的可能取值,从中选取使目标函数取得极值(极大或极小)的节点优先进行广度搜索,从而不断调整搜索方向,尽快找到问题的解。
由于限界函数一般基于问题的目标函数决定,因此,分支限界法适用于求解最优解问题或者较小代价找出满足条件的答案解。

你可能感兴趣的:(解题笔记)