算法设计与分析第七章分支限界算法

一、分支界限算法概述

1、分支限界法类似于回溯法,是一种在问题的解空间树上搜索问题解的算法。
分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优解。
分支限界法常以广度优先的方式搜索问题的解空间树。
2、在分支限界法中,每一个活结点只有一次机会成为扩展结点。
活结点一旦成为扩展结点,就一次性产生其所有儿子结点。在这些儿子结点中,导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。
此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结点扩展过程。这个过程一直持续到找到所需的解或活结点表为空时为止。
3、分支节点的选择-常见的两种分支限界法
从活结点表中选择下一扩展结点的不同方式导致不同的分支限界法:
(1)、队列式(FIFO)分支限界法:按照队列先进先出(FIFO)原则选取下一个节点为扩展节点。
(2)、优先队列式分支限界法:按照优先队列中规定的优先级选取优先级最高的节点成为当前扩展节点。
最大优先队列:使用最大堆,体现最大效益优先
最小优先队列:使用最小堆,体现最小费用优先

二、分支界限有关例题

1、数字细胞

问题描述:
一矩形阵列由数字0到9组成,数字1到9代表细胞,细胞的定义为沿细胞数字上下左右还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。如:
阵列
4 10
0234500067
1034560500
2045600671
0000000089
有4个细胞。
问题分析:

按照上下左右的顺序进行检查,并将符合条件的依次入队。
解空间是一棵四叉树。

为避免一个细胞被重复检查,需要将检测过的细胞数字清0
依次遍历二维数组,完成细胞数目的检测
⑴从文件中读入m*n矩阵阵列,将其转换为boolean矩阵存入bz数组中;
⑵沿bz数组矩阵从上到下,从左到右,找到遇到的第一个细胞;
⑶将细胞的位置入队h,并沿其上、下、左、右四个方向上的细胞位置入队,入队后的位置bz数组置为false;
⑷将h队的队头出队,沿其上、下、左、右四个方向上的细胞位置入队,入队后的位置bz数组置为false;
⑸重复4,直至h队空为止,则此时找出了一个细胞;
⑹重复2,直至矩阵找不到细胞;
⑺输出找到的细胞数。
代码:

#include<cstdio>
using namespace std;
int dx[4]={-1,0,1,0},   // x,y 方向上的增量dy[4]={0,1,0,-1};
int bz[100][100],num=0,n,m;   //二维数组,存储原始矩阵
void doit(int p,int q){  //p,q矩阵的行列号int x,y,t,w,i;int h[1000][2];  //顺序队列,记录入队细胞元素在二维数组中的位置num++;  //细胞个数增1bz[p][q]=0;  //细胞元素清0t=0;w=1;  //队列指针。t队首,w 队尾h[1][1]=p;  h[1][2]=q;       //遇到的第一个细胞入队do    {t++;                                    //队头指针加1for (i=0;i<=3;i++){     //沿细胞的上下左右四个方向搜索细胞x=h[t][1]+dx[i];y=h[t][2]+dy[i];if ((x>=0)&&(x<m)&&(y>=0)&&(y<n)&&(bz[x][y])){w++;h[w][1]=x;  h[w][2]=y;           bz[x][y]=0;}                                          //本方向搜索到细胞就入队}}while (t<w);                             //直至队空为止
}
int main(){int i,j;char s[100],ch;scanf("%d%d\n",&m,&n);for (i=0; i<=m-1;i++ )for (j=0;j<=n-1;j++ )bz[i][j]=1;                              //初始化for (i=0;i<=m-1;i++)    {gets(s);for (j=0;j<=n-1;j++)        if (s[j]=='0') bz[i][j]=0;}for (i=0;i<=m-1;i++)for (j=0;j<=n-1;j++)if (bz[i][j])        doit(i,j);                                //在矩阵中寻找细胞printf("NUMBER of cells=%d",num);return 0;
}

2、棋子最少步数

问题描述:
在各种棋中,棋子的走法总是一定的,如中国象棋中马走“日”。有一位小学生就想如果马能有两种走法将增加其趣味性,因此,他规定马既能按“日”走,也能如象一样走“田”字。他的同桌平时喜欢下围棋,知道这件事后觉得很有趣,就想试一试,在一个(100*100)的围棋盘上任选两点A、B,A点放上黑子,B点放上白子,代表两匹马。棋子可以按“日”字走,也可以按“田”字走,俩人一个走黑马,一个走白马。谁用最少的步数走到左上角坐标为(1,1)的点时,谁获胜。现在他请你帮忙,给你A、B两点的坐标,想知道两个位置到(1,1)点可能的最少步数。【输入样例】
  12 16
18 10
【输出样例】
  8
9
问题分析:
1、搜索空间
从(1,1)计算到达A, B位置的最小值
如果两个A, B均以计算,算法停止

2、数据结构
设queue——队列,存储从(1,1)可达的点(queue[k][1…2])以及到达该点所需要的最少步数(queue[k][3])(0≤k≤192+1)。队列的首指针为head,尾指针为tail。初始时,queue中只有一个元素为(1,1),最少步数为0。
S[][] —记录(1,1)到每点所需要的最少步数。显然,问题的答案是s[x1][y1]和s[x2][y2]。初始时,s[1][1]为0,除此之外的所有元素值设为-1。
3、约束条件
⑴不能越出界外。由于马的所有可能的落脚点s均在s的范围内,因此一旦马越出界外,就将其s值赋为0,表示“已经扩展过,且(1,1)到达其最少需要0步”。这看上去是荒谬的,但可以简单而有效地避免马再次落入这些界外点。
⑵该点在以前的扩展中没有到达过。如果曾经到达过,则根据广度优先搜索的原理,先前到达该点所需的步数一定小于当前步数,因此完全没有必要再扩展下去。
由此得出,马的跳后位置(x,y)是否可以入队的约束条件是s[x][y]<0。
代码:

#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
int dx[12]={-2,-2,-1,1,2,2,2,2,1,-1,-2,-2},dy[12]={-1,-2,-2,-2,-2,-1,1,2,2,2,2,1};
int main(){int s[101][101],que[10000][4]={0},x1,y1,x2,y2;memset(s,0xff,sizeof(s));             //s数组的初始化int head=1,tail=1;                         //初始位置入队que[1][1]=1;que[1][2]=1;que[1][3]=0;cin>>x1>>y1>>x2>>y2;               //读入黑马和白马的出发位置while(head<=tail) {                        //若队列非空,则扩展队首结点for(int d=0;d<=11;d++){                //枚举12个扩展方向int x=que[head][1]+dx[d];     //计算马按d方向跳跃后的位置int y=que[head][2]+dy[d];
if(x>0&&y>0&&x<=100&&y<=100)if(s[x][y]==-1)  {                 //若(x,y)满足约束条件s[x][y]=que[head][3]+1;     //计算(1,1)到(x,y)的最少步数tail++;                        //(1,1)至(x,y)的最少步数入队que[tail][1]=x;que[tail][2]=y;que[tail][3]=s[x][y];if(s[x1][y1]>0&&s[x2][y2]>0){  //输出问题的解cout<<s[x1][y1]<<endl;cout<<s[x2][y2]<<endl;system("pause");return 0;}}
}head++;}}

*** 运行结果:***

3、单元路径最短问题

问题描述:
给定带权有向图G=(V,E),其中每条边的权是非负实数。给定V中的一个顶点,称为源。
现在要计算从源到所有其它各顶点的最短路长度,这里路的长度是指路上各边权之和。这个问题通常称为单源最短路径问题。
每条边上标注有字母和数字,在字母旁边的数字为路长。

问题分析:

算法从优先队列中取出具有最小当前路长的结点作为当前扩展结点,并依次检查与当前扩展结点相邻的所有顶点。
剪枝规则:
如果从当前扩展结点i到顶点j有边可达,且从源出发,途经顶点i再到顶点j相应的路径的长度小于当前最优路径长度,则将该顶点作为活结点插入到活结点优先队列中。


算法从优先队列中取出具有最小当前路长的结点作为当前扩展结点,并依次检查与当前扩展结点相邻的所有顶点。
如果从当前扩展结点i到顶点j有边可达,且从源出发,途经顶点i再到顶点j相应的路径的长度小于当前最优路径长度,则将该顶点作为活结点插入到活结点优先队列中。




这个结点的扩展过程一直继续到活结点优先队列为空。


这个结点的扩展过程一直继续到活结点优先队列为空。

代码:

#include <iostream>
#include <string>
#include <queue>
using namespace std;
class Graphic{int n;//图中顶点的个数int e;//边的数目int **adjmatrix;//邻接矩阵,存储图int *dist;//dist[n],存储单元点到其他n-1个顶点的最短路的长度int  *prev;//prev[i]=j 存储顶点i 的前驱结点为j , 利用这些前驱结点可以找到源点到顶点i的最短路int start;//源点
public:Graphic(int n, int e);void ShortPath();void display();
};
class PathNode{ //放入优先队列中的节点,解空间中的结点int i; //解空间中结点的编号。一个结点对应于一条路int length;//路的长度。friend class Graphic;
public:PathNode(int a=0, int b=0):i(a),length(b){}bool operator <(PathNode b) const {//定义优先关系函数return length>b.length;}
};
Graphic::Graphic(int n, int e){this->n=n;   this->e=e;adjmatrix=new int*[n+1];dist=new int[n+1];    prev=new int[n+1];for(int i=1;i<=n;i++)    adjmatrix[i]=new int[n+1];cout<<"输入源点编号:"; cin>>start;cout<<"请输入e条边"<<endl;for(int i=1;i<=n;i++){ //邻接矩阵初始化for(int j=1;j<=n;j++)adjmatrix[i][j]=-1;  //两个顶点之间没有边adjmatrix[i][i]=0;}for( int i=0;i<e;i++) {int a, b,length;cin>>a>>b>>length; //输入一条边所依附的两个顶点和这条边的长度adjmatrix[a][b]=length; //有向图dist[i]=99999; //最短路赋初值prev[i]=start;}
};
void Graphic::ShortPath() {priority_queue<PathNode> q;PathNode first,next;first.i=start;  //计算顶点v到其它顶点的最短路first.length=0;prev[start]=0;    dist[start]=0; q.push(first);while(true)   {if(q.empty())   break;first=q.top(); q.pop();for(int i=1;i<=n;i++){// 搜索孩子结点,并将可行的结点插入优先队列if(adjmatrix[first.i][i]>0 && (first.length+adjmatrix[first.i][i])<dist[i]){   dist[i]=first.length+adjmatrix[first.i][i];prev[i]=first.i;next.i=i;next.length=dist[i];q.push(next);}     }   }   }
void Graphic::display(){for (int i=1;i<=n;i++)       {cout<<"源点1 到顶点"<<i<<"的最短路长度为"<<dist[i]<<"如下:";int j;j=i;cout<<j;while(j) {cout<<"->"<<prev[j];j=prev[j];}cout<<endl;}
}
int main(){int n,e;cin>>n>>e;Graphic g(n,e);g.ShortPath();g.display();return 0;
}

算法设计与分析第七章分支限界算法(完结篇)相关推荐

  1. 算法设计与分析第3章 贪心算法

    第4章 贪心算法 贪心算法总是作出在当前看来最好的选择.也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择. 贪心算法的基本要素 1.贪心选择性质 所谓贪心选择性质是指所 ...

  2. PTA(二十五) 算法设计与分析 第七章 贪心法 7-1 装箱问题 (20 point(s))

    7-1 装箱问题 (20 point(s)) 假设有N项物品,大小分别为s1.s2.-.sN,其中s​i为满足1≤s​i​​ ≤100的整数.要把这些物品装入到容量为100的一批箱子(序号1-N)中. ...

  3. 计算机算法设计与分析第五章思维导图知识点总结 ( 初稿 )

    复习链接 计算机算法设计与分析第一章思维导图 计算机算法设计与分析第二章思维导图&&知识点总结 计算机算法设计与分析第三章思维导图&&知识点总结 计算机算法设计与分析第 ...

  4. 算法设计与分析——十大经典排序算法二(6--10)

    一个不知名大学生,江湖人称菜狗 original author: jacky Li Email : 3435673055@qq.com  Time of completion:2023.3.1 Las ...

  5. 算法设计与分析_[04] 天牛须算法设计思想分析

    原文链接: https://arxiv.org/abs/1710.10724​arxiv.org 算法实现: 首先,初始化参数 ,分别代表初始解,初始的搜索范围,以及更新步长,且通过原文我们知道: 在 ...

  6. 算法设计与分析第5章 回溯法(二)【回溯法应用】

    第5章 回溯法 5.2 应用范例 1.0-1背包问题 有n件物品和一个容量为c的背包.第i件物品的重量是w[i],价值是p[i].求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和 ...

  7. 算法设计与分析基础 第一章谜题

    习题1.1 10.b 欧几里得游戏 一开始,板上写有两个不相等的正整数,两个玩家交替写数字,每一次,当前玩家都必须在板上写出任意两个板上数字的差,而且这两个数字必须是新的,也就是说,不能与板上任何一个 ...

  8. [XJTUSE 算法设计与分析] 第五章 回溯法

    第五章 回溯法 填空题会有代码填空,大题会手动回溯 学习要点 理解回溯法的深度优先搜索策略. 掌握用回溯法解题的算法框架 (1)递归回溯 (2)迭代回溯 (3)子集树算法框架 (4)排列树算法框架 5 ...

  9. (算法设计与分析)第一章算法概述-第一节:算法基本概念和算法复杂性分析

    文章目录 一:算法与程序 (1)算法的定义 (2)算法的五大特征 (3)算法与程序的区别 (4)算法的描述方法 二:算法复杂性分析 (1)时间复杂度 A:算法时间复杂度表示方法 B:表示算法渐进时间复 ...

最新文章

  1. 近万个Python开源项目中精选Top34!
  2. 重磅直播|多模态融合SLAM技术分享!
  3. LENOVO 充到60%就会停止充电
  4. git、github、gitlab、gitee都是什么?
  5. 关于编译FFMPEG的初级教程
  6. Undedared identifier问题解决
  7. css连续选取几个li_CSS高级选择器:nth-child()应用大全
  8. linux安装Linux下软件的安装与卸载方法
  9. 1.语音增强技术概述
  10. 帆软实现分页时第一行和最后两行冻结方式
  11. 利用0day-java环境-宏感染-安卓客户端进行渗透
  12. 前端vue中ts无法识别引入的vue文件,提示找不到xxx.vue模块的解决【引入新建页面或者通过router引入时报错】
  13. Ubuntu Desktop - Disks
  14. electron实现屏幕录制
  15. C# 如何取得本机网卡的型号,IP地址,子网掩码和网关
  16. CGB2107-Day03-mybatis
  17. 【干货收藏】 IGBT 的国产替代
  18. 衡水中学计算机老师,衡水中学资深老师:电脑阅卷本就是一种淘汰机制,学生都不以为然...
  19. vue引入个性化字体
  20. 百度竞价排名曝光_全球塑胶网:百度爱采购模式推广效果怎么样?

热门文章

  1. 在启动MYSQL时出现问题:“ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost' (10061)”
  2. 211毕业生3天被辞退:offer不等于工作稳了!
  3. python 括号 中 不需要 反斜杠_如何消除反斜杠后的空白(Python3.4)
  4. Android实现mp3音频剪辑(带试听)
  5. 竞赛资讯|A股上市公司季度营收预测
  6. 《算法导论》习题5.3-1 ~ 5.3-7
  7. A*/AStar规划算法(C++版本)
  8. 智慧交通大数据可视化,让城市运营车辆可视、可监、可控
  9. SQL server Date函数之DATEADD()函数
  10. 工作站压力测试软件,胜任多种工作负载 联想P500工作站评测