10月24日周末总结

本文探讨了在搜索算法中的几种优化技术,包括康拓展开用于判重,A*算法结合贪心思想减少运算,双向广搜寻找状态变化路径,以及迭代加深搜索与IDA*算法在处理无限或大规模数据时的策略。这些方法通过减少运算量和提高效率,有效地解决了复杂问题。
摘要由CSDN通过智能技术生成

搜索优化

康拓展开

康拓展开是一种在全排列中数值与所处位置的对应关系的展示,可以在搜索算法中起到判重的作用,这样可以大大缩短运算量。
举例说明一下:有12345这5个数,给出21543,根据康拓展开可以求出这是位于字典序中的第几大数,首先从第一个数开始,比它小的只有1,后面还有4!种,所以是14!种,再看下一位数,没有比1小的,这样只有03!,以此类,就可以得到比当前这个数的字典序。(注意:这里不仅要求是比当前位的数小,还要求被比较的数没有出现过,所以只需要让当前位的数与在他之后的每一位数作比较即可)

long int factory[]={1,1,2,6,24,120,720,5040,40320,362880};
bool flag[362880];
bool cantor(int str[],int n)
{
    long result=0;
    for(int i=1;i<=n;i++)
    {
        int counted=0;
        for(int j=i;j<n;j++)
        {
            if(str[i]>str[j])
                counted++;
             //看看这一位的数在未出现的数中第几大
        }
        result+=counted*factory[n-i-1];//康拓公式的运用
    }
    if(!flag[result])
    {
        flag[result]=1;
        return 1;
    }
    else return 0;
}

针对八位数字的判重,这里定义的factory数组记录了0到8的情况即提前将对应的阶乘部分乘数放入数组内,减少运算量。

A*算法

这个是非常好理解的一个概念,即在搜索中加入贪心的算法,将超出最优解的情况排除,达到减少运算量的目的,最简单的就是引入曼哈顿距离(即两点之间纵坐标差与横坐标差之和)
可以在搜索中引入评估函数:f(x)=g(x)+h(x),g(x)表示初始状态到当前状态的实际代价,h(x)表示当前状态到最终状态的最优解(也被称为启发函数)这说明。h(x)决定了整个算法的优劣。
如果g(x)=0,那么就是f(x)=h(x),也就是纯粹的贪心算法,没有搜索的帮助下可能会陷入局部最优而无法得到答案(无法考虑每个位置的情况),如果h(x)=0,那么就是f(x)=g(x),又变成了纯粹的搜索,这样运算量又会加大。

双向广搜

这个是广搜算法的优化,即从两头开始进行搜索,这样只需要查看中间是否出现了交点,可以适用于判断能否在固定步数内完成状态的变化。(可以使用双向队列作为辅助)

迭代加深搜索

这个我个人认为对题目的限制要求较高,只针对于那些可能会出现无限或者数据巨大的情况,比如埃及数这道题(给出一个有理数,让他由分数组成,要求分数最少的情况,同时最小的分数尽可能大)这道题的数据范围就是无限的,这样即使是深搜还是广搜都是会爆的,这时候可以对dfs的范围进行限制,从第一层开始广搜,然后是第二层,第三层,这样直接避免了dfs的弊端。

IDA*

这个是将上面两种算法结合使用,在迭代加深搜索的同时给出启示函数,目的都是减少运算量

#include <iostream>
#include <cmath>
using namespace std;
int val[1010]={0};
int pos,depth;
int n;
bool ida(int now,int depth)
{
	if(now>depth) return false;//第一次剪枝,如果超出当前迭代范围,直接退出
	if(val[pos]<<(depth-now)<n) return false;//第二次剪枝,估价函数,也是启示函数,即当前数以2的倍数增长,也就是最大到达的数值,如果小于目标直接退出
	if(val[pos]==n) return true;//返回得到结果
	pos++;
	for(int i=0;i<pos;i++)//深搜部分
	{
		val[pos]=val[pos-1]+val[i];//深搜的范围:这个数与已知任意数的一次加或减运算
		if(ida(now+1),depth) return true;
		val[pos]=abs(val[pos-1]-val[i]);
		if(ida(now+1),depth) return true;
	}
	pos--;//未能找到结果,返回上次的状态
	return false;
}
int main()
{
	while(cin>>n&&n!=0)
	{
		depth=0;
		for(depth=0;;depth++)//迭代部分核心代码,控制当前搜索深度
		{
			val[0]=1;
			pos=0;
			if(ida(0,depth))
			break;
		}
		cout<<depth<<endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值