搜索-BFS(广搜)(21.8.1)

搜索,就是列举所有情况,一种一种的列,但是在当前情况下又会分成好几个状态,还要继续列举,状态,每一个状态都会有一个可能解,从一个状态转移到另一个状态,进行搜索的进一步延伸,

一、BFS和队列

一般用队列来实现广搜
找出所有的大情况,再把每种大情况的下一阶段找出,一层一层的寻找,广搜离不开队列,可以求最短路径

算是一个模板吧
struct node
{
    int xx,yy,step;
};
void bfs(int xx,int yy)
{
    queue<node>q;
    memset(v,0,sizeof(v));
    node s,ss;
    s.xx=xx;
    s.yy=yy;
    s.step=0;
    q.push(s);//赋初始值
    while(!q.empty())
    {
        s=q.front();//取队首元素
        q.pop();//删除队首元素
        for(int i=0;i<12;i++)//把移动方式全部执行一遍
        {
            r=s.xx+x[i];
            l=s.yy+y[i];
            if(r<=100&&r>0&&l<=100&&l>0&&v[r][l]==0)//符合范围条件且未走过
            {
                v[r][l]=1;//标记走过
                ss.xx=r;
                ss.yy=l;
                ss.step=s.step+1;
                q.push(ss);//放入移动后的信息
                if(r==1&&l==1)
                {
                    cout<<s.step+1<<endl;
                    return ;
                }
            }
        }
    }
}
二、八数码问题和状态图搜索

BFS搜索处理的对象换成“状态”,即状态图搜索问题

1、八数码问题是典型的状态图搜索问题

在3×3的棋盘上,摆上标有1至8的某一数字的八个棋子。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局和目标布局,计算出最少移动步数和数码的移动数列。

我们回想一下普通的广搜,就是把所有情况都列举一遍,里面必定会有重复的状态,但这一棋局共有9!种状态,一遍一遍的查重又非常繁琐,所以用“康托展开”来判重(利用哈希函数)。

2、康托展开

康托展开的功能是:计算出给出排列数的相应位置
例如,总共有9!个数,第一个数的位置是0,以此类推最后一个数的位置就是9!-1,康托函数就是把排列,转化成相对应的位置
然后用这个函数判断每一个新状态是否已经处理过了(详细的原理就不说了)
直接写用法

int factorial[20]={1,1,2,6,24,120,720,5040,40320,362880,3628800}; //cantor需要用到的常数,固定的
int flag[20];//标记数组
bool cantor(int num[],int n)//康托函数
{
	int x=0;
	for(int i=0;i<n;i++){//遍历num数组 
		int cot=0;
		for(int j=i+1;j<n;j++)//找到小于num[i]的数字
		{
			if(num[i]>num[j])  cot++;//计算未出现的元素排在第几个
		}
		x+=cot*factorial[n-i-1]; 
	}
	if(!flag[x]) 
	{
	    flag[x]=1;
	    return 1;
	}
	else return 0;
}

补充:给出全排列后,给出一个数字k,返回第k大的排列,就是逆康托展开(暂不使用,先放着吧)

3、A* 算法

启发式搜索,A*算法=“BFS+贪心”
曼哈顿距离就是起点和终点的横纵坐标距离之和

三、双向广搜(DBFS)

双向广搜从起点(正向搜索)和终点(逆向搜索)同时开始搜索,直到在某个位置遇到。前提是直到起点和终点
哦,没有代码,有空粘

总结:之前在学校没好好学搜索,也没做过题,现在重新学习,发现书上很多新名词和新型的算法,因为做题经验太少,不知道是不是所有的都很有必要去学习,如果一直往外拓展延伸会花费太多时间,毕竟时间还是很紧张的,所以先把一些莫名其妙的太陌生的方法放弃,如果做题的时候用到再重新接触和学习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值