双向广度优先搜索算法是对广度优先算法的一种扩展。广度优先算法从起始节点以广度优先的顺序不断扩展,
直到遇到目的节点;而双向广度优先算法从两个方向以广度优先的顺序同时扩展,一个是从起始节点开始扩展,另
一个是从目的节点扩展,直到一个扩展队列中出现另外一个队列中已经扩展的节点,也就相当于两个扩展方向出现了
交点,那么可以认为我们找到了一条路径。双向广度优先算法相对于广度优先算法来说,由于采用了从两个跟开始扩展
的方式,搜索树的深度得到了明显的减少,所以在算法的时间复杂度和空间复杂度上都有较大的优势!双向广度优先算
法特别适合于给出了起始节点和目的节点,要求他们之间的最短路径的问题。另外需要说明的是,广度优先的顺序能够保证
找到的路径就是最短路径!
基于以上思想,我们给出双向广度优先算法编程的基本框架如下:
数据结构:
Queue q1, q2; //两个队列分别用于两个方向的扩展(注意在一般的广度优先算法中,只需要一个队列)
int head[2], tail[2]; //两个队列的头指针和尾指针
算法流程:
一、主控函数:
void solve()
{
1. 将起始节点放入队列q1,将目的节点放入队列q2
2. 当 两个队列都未空时,作如下循环
1) 如果队列q1里的未处理节点比q2中的少(即tail[0]-head[0] < tail[1]-head[1]),则扩展(expand())队列q1
2) 否则扩展(expand())队列q2 (即tail[0]-head[0] >= tail[1]-head[1]时)
3. 如果队列q1未空,循环扩展(expand())q1直到为空
4. 如果队列q2未空,循环扩展(expand())q2知道为空
}
二、扩展函数:
int expand(i) //其中i为队列的编号(表示q0或者q1)
{
取队列qi的头结点H
对头节点H的每一个相邻节点adj,作如下循环
1 如果adj已经在队列qi之前的某个位置出现,则抛弃节点adj
2 如果adj在队列qi中不存在[函数 isduplicate(i)]
1) 将adj放入队列qi
2) 如果adj 在队列(q(1-i)),也就是另外一个队列中出现[函数 isintersect()]
输出 找到路径
}
三、判断新节点是否在同一个队列中重复的函数
int isduplicate(i, j) //i为队列编号,j为当前节点在队列中的指针
{
遍历队列,判断是否存在【线性遍历的时间复杂度为O(N),如果用HashTable优化,时间复杂度可以降到O(1)]
}
四、判断当前扩展出的节点是否在另外一个队列出现,也就是判断相交的函数:
int isintersect(i,j) //i为队列编号,j为当前节点在队列中的指针
{
遍历队列,判断是否存在【线性遍历的时间复杂度为O(N),如果用HashTable优化,时间复杂度可以降到O(1)]
}
以上为双向广度优先搜索算法的基本思路,下面给出使用上面的算法框架编写的八数码问题的代码:
问题描述:
给定 3 X 3 的矩阵如下:
2 3 4
1 5 x
7 6 8
程序每次可以交换"x"和它上下左右的数字,
经过多次移动后得到如下状态:
1 2 3
4 5 6
7 8 x
输出在最少移动步数的情况下的移动路径[每次移动的方向上下左右依次表示为'u', 'd', 'l', 'r']
例如:
如果过输入:【将矩阵放到一行输出】
2 3 4 1 5 x 7 6 8
则输出:
ullddrurdllurdruldr
原题见ACM PKU 1077
C++代码如下:【注意,这是没有使用HASH优化的版本,压线通过了ACM PKU在线测试的内存和时间要求】
/*
* Author: puresky
* Date: 2010.01.12
* Purpose: solve EIGTH NUMBER problem!
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 1000000
#define SWAP(a, b) {char t = a; a = b; b = t;}
typedef struct _Node Node;
struct _Node
{
char tile[10]; // represent the tile as a string ending with '\0'
char pos; // the position of 'x'
char dir; //the moving direction of 'x'
int parent; //index of parent node
};
int head[2], tail[2];
Node queue[2][MAXN];// two queues for double directoin BFS
//shift of moving up, down, left ,right
int shift[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
//for output direction!
char dir[4][2] = {{'u', 'd'}, {'d', 'u'}, {'l', 'r'}, {'r', 'l'}};
//test case
char start[10] = "23415x768";
char end[10] = "12345678x";
//read a tile 3 by 3
void readtile()
{
int i;
char temp[10];
for(i = 0; i < 9; ++i)
{
scanf("%s", temp);
start[i] = temp[0];
}
start[9] = '\0';
}
//print result
void print_backward(int i)
{
if(queue[0][i].parent != -1)
{
print_backward(queue[0][i].parent);
printf("%c", queue[0][i].dir);
}
}
void print_forward(int j)
{
if(queue[1][j].parent != -1)
{
printf("%c", queue[1][j].dir);
print_forward(queue[1][j].parent);
}
}
void print_result(int i, int j)
{
//printf("%d,%d\n", i, j);
print_backward(i);
print_forward(j);
printf("\n");
}
//init the queue
void init(int qi, const char* state)
{
strcpy(queue[qi][0].tile, state);
queue[qi][0].pos = strchr(state, 'x') - state;
queue[qi][0].parent = -1;
head[qi] = tail[qi] = 0;
}
//check if there are duplicates in the queue
//time comlexity:O(n)
//We can optimise this function using HashTable
int isduplicate(int qi)
{
int i;
for(i = 0; i < tail[qi]; ++i)
{
if(strcmp(queue[qi][tail[qi]].tile, queue[qi][i].tile) == 0)
{
return 1;
}
}
return 0;
}
//check if the current node is in another queue!
//time comlexity:O(n)
//We can optimise this function using HashTable
int isintersect(int qi)
{
int i;
for(i = 0 ; i < tail[1 - qi]; ++i)
{
if(strcmp(queue[qi][tail[qi]].tile, queue[1 - qi][i].tile) == 0)
{
return i;
}
}
return -1;
}
//expand nodes
int expand(int qi)
{
int i, x, y, r;
Node* p = &(queue[qi][head[qi]]);
head[qi]++;
for(i = 0; i < 4; ++i)
{
x = p->pos / 3 + shift[i][0];
y = p->pos % 3 + shift[i][1];
if(x >= 0 && x <= 2 && y >= 0 && y <= 2)
{
tail[qi]++;
Node* pNew = &(queue[qi][tail[qi]]);
strcpy(pNew->tile, p->tile);
SWAP(pNew->tile[ 3 * x + y], pNew->tile[p->pos]);
pNew->pos = 3 * x + y;
pNew->parent = head[qi] - 1;
pNew->dir = dir[i][qi];
if(isduplicate(qi))
{
tail[qi]--;
}
else
{
if((r = isintersect(qi)) != -1)
{
if(qi == 1)
{
print_result(r, tail[qi]);
}
else
{
print_result(tail[qi], r);
}
return 1;
}
}
}
}
return 0;
}
//call expand to generate queues
int solve()
{
init(0, start);
init(1, end);
while(head[0] <= tail[0] && head[1] <= tail[1])
{
//expand the shorter queue firstly
if(tail[0] - head[0] >= tail[1] - head[1])
{
if(expand(1)) return 1;
}
else
{
if(expand(0)) return 1;
}
}
while(head[0] <= tail[0]) if(expand(0)) return 1;
while(head[1] <= tail[1]) if(expand(1)) return 1;
return 0;
}
int main(int argc, char** argv)
{
readtile();
if(!solve())
{
printf("unsolvable\n");
}
//system("pause"); //pause
return 0;
}
ACM Judge Online: 372K 内存, 938MS 时间
使用HASHTABLE优化后的版本见:《八数码问题HashTable优化查找后的版本》
分享到:
相关推荐
oracle的框架主要由物理结构、逻辑结构、内存分配、后台进程、oracle例程、系统改变号 (System Change Number)组成 物理结构 物理结构包含三种数据文件: 1) 控制文件 2) 数据文件 3) 在线重做日志文件 ...
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。
《基于YOLOv8的智慧社区独居老人生命体征监测系统》(包含源码、可视化界面、完整数据集、部署教程)简单部署即可运行。功能完善、操作简单,适合毕设或课程设计
Android Studio Meerkat 2024.3.1 Patch 1(android-studio-2024.3.1.14-mac.dmg)适用于macOS Intel系统,文件使用360压缩软件分割成两个压缩包,必须一起下载使用: part1: https://download.csdn.net/download/weixin_43800734/90557060 part2: https://download.csdn.net/download/weixin_43800734/90557056
侧轴承杯加工工艺编制及夹具设计.zip
NASA数据集锂电池容量特征提取(Matlab完整源码和数据) 作者介绍:机器学习之心,博客专家认证,机器学习领域创作者,2023博客之星TOP50,主做机器学习和深度学习时序、回归、分类、聚类和降维等程序设计和案例分析,文章底部有博主联系方式。从事Matlab、Python算法仿真工作8年,更多仿真源码、数据集定制私信。
板料折弯机液压系统设计.zip
C6150车床的设计.zip
机器学习之KNN实现手写数字
python爬虫;智能切换策略,反爬检测机制
mpls-vpn-optionA-all
56tgyhujikolp[
GB 6442-86企业职工伤亡事故调查分析规则.pdf
汽车液压式主动悬架系统的设计().zip
2000-2024年各省专利侵权案件结案数数据 1、时间:2000-2024年 2、来源:国家知识产权J 3、指标:专利侵权案件结案数 4、范围:31省 5、用途:可用于衡量知识产权保护水平
资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。
内容概要:本文档详细复现了金融数学课程作业,涵盖欧式看涨期权定价和投资组合优化两大部分。对于欧式看涨期权定价,分别采用Black-Scholes模型和蒙特卡洛方法进行了计算,并对彩虹期权进行了基于最大值的看涨期权定价。投资组合优化部分则探讨了最小方差组合、给定收益的最小方差组合、最大效用组合以及给定风险的最大收益组合四种情形,还对比了拉格朗日乘数法和二次规划求解器两种方法。文中不仅提供了详细的MATLAB代码,还有详尽的中文解释,确保每一步骤清晰明了。 适合人群:金融工程专业学生、量化分析师、金融数学爱好者。 使用场景及目标:①帮助学生理解和掌握金融衍生品定价的基本原理和方法;②为从事量化分析的专业人士提供实用工具和技术支持;③作为教学材料辅助高校教师讲授相关内容。 其他说明:文档还包括了完整的论文结构建议,从封面页到结论,再到附录,涵盖了所有必要元素,确保提交的作业符合学术规范。此外,还特别强调了数据预处理步骤,确保代码可以顺利运行。
脉冲电解射流加工喷射装置设计(1)
ThinkPad S1 (2nd Generation) 和ThinkPad Yoga 260 用户指南V3.0,包含如何拆机更换硬件
charles描述文件下载