挂在天上放光明,好像一群IDA*

学了A怎么能补血IDA??

IDA*

前置芝士🧀

想吃芝士蛋糕惹QAQ

ID(迭代加深搜索)(from:OIwiki);

定义

迭代加深是一种 每次限制搜索深度深度优先搜索;

解释

迭代加深搜索的本质还是深度优先搜索,只不过在搜索的同时带上了一个深度 \(d\),当\(d\) 达到设定的深度时就返回,一般用于找最优解。如果一次搜索没有找到合法的解,就让设定的深度加一,重新从根开始

既然是为了找最优解,为什么不用 \(BFS\) 呢?我们知道 \(BFS\) 的基础是一个队列,队列的空间复杂度很大,当状态比较多或者单个状态比较大时,使用队列的 \(BFS\) 就显出了劣势。事实上,迭代加深就类似于用 \(DFS\) 方式实现的 \(BFS\),它的空间复杂度相对较小。

当搜索树的分支比较多时,每增加一层的搜索复杂度会出现指数级爆炸式增长,这时前面重复进行的部分所带来的复杂度几乎可以忽略,这也就是为什么迭代加深是可以近似看成 \(BFS\) 的。

过程

首先设定一个较小的深度作为全局变量,进行 \(DFS\)。每进入一次 \(DFS\),将当前深度加一,当发现 \(d\) 大于设定的深度 \(limit\) 就返回。如果在搜索的途中发现了答案就可以回溯,同时在回溯的过程中可以记录路径。如果没有发现答案,就返回到函数入口,增加设定深度,继续搜索。

A*

请见上篇一闪一闪亮晶晶,满天都是A*
发现:
A*算法需要去维护一个优先队列来存储状态,有时会MLE,并且对堆进行一次操作需要花费\(O(\log N)\)的时间。不是很优,考虑优化。

IDA*

定义

(大雾):

\[IDA^*\ne ID+A^* \]

\[IDA^*=h+ID \]

IDA* 算法其实是同时运用迭代加深全局最优性剪枝
IDA* 是在DFS中 加入估价函数\(h\) 再考虑迭代加深。

原理及实现

观察A*中的\(f^*\)函数

  • \(f^∗\)函数:从起点当前点再到终点估计距离。

\[f^∗=g^∗+h^∗=g+h^∗ \]

(其函数定义与A* 相同)
使用DFS,若其函数值大于你的规定深度\(d\),就进行回溯操作。

规定深度\(d\)DFS动态更新。初始规定深度\(d\)取为起点的总成本估计值\(h(s)\)

在一次DFS中,每当因超过规定深度\(d\)而停止时,就记录所有尚未访问的后继结点的总成本估计的最小值。

DFS结束后,将规定深度\(d\)更新为这一最小值,继续下一轮DFS

例题

洛谷 P10488 [BAPC 2006 资格赛] Booksort

image

思路

爆爆爆爆爆爆搜 ,T T T T T L E 。
考虑优化,发现可以使用爱地欸star,考虑如何构造估计函数,记录变量\(tot\)骨头错位的书的本数,考虑正骨调换一次\((l-r)\)带来的贡献是多少,发现会改变\(3\)本书的(相对)位置:

  1. \(l\) 这本书
  2. \(r\) 这本书
  3. \(r+1\) 这本书

所以

\[h=\lceil \frac{tot}{3}\rceil \]

剩下的去看代码吧!

代码

#include<bits/stdc++.h>
using namespace std;
int n;
int a[20],mv[6][20];
int h()//估计函数 
{
	int tot=0;
	for(int i=1;i<n;i++)
	{
		if(a[i]+1!=a[i+1])
		{
			tot++;
		}
	}
	return (tot+2)/3;
}
bool dfs(int x,int md)//当前深度,最大深度 
{
	if(x+h()>md)//回溯 
	{
		return 0;
	}
	if(h()==0)//已经排好序了 
	{
		return 1;
	}
    for(int len=1;len<=n;len++)//枚举长度 
	{
	    for(int l=1;l+len<=n+1;l++)//枚举左端点 
	    {
	    	int r=l+len-1;
	    	for(int k=r+1;k<=n;k++)//枚举插入位置 
	    	{
	    		memcpy(mv[x],a,sizeof(a));//将状态记录 
	    		//以下是交换的后的状态更改 
	    		//实现的是拿出l~r,放到k(即l~r,r+1~k互换位置) 
				int i=l;
	    		for(int j=r+1;j<=k;i++,j++)//将r+1~k放到l-1位后面 
	    		{
	    			a[i]=mv[x][j];
				}
				for(int j=l;j<=r;i++,j++)//将l~r放到插入点k后面 
				{
					a[i]=mv[x][j];
				}
				if(dfs(x+1,md))//扩展到了答案 
				{
					return 1;
				}
				memcpy(a,mv[x],sizeof(a));//回退,返回扩展前的状态 
			}
		}
	} 
	return 0;
}
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
	    cin>>n;
		for(int i=1;i<=n;i++)
		{
		    cin>>a[i];
		}	
		int d=h();//规定深度 
		while(d<5&&!dfs(0,d))
		{
			d++;
		}
		if(d>=5)
		{
			cout<<"5 or more"<<endl;
		}
		else
		{
			cout<<d<<endl;
		}
	} 
	return 0;
}

委婉戴旭

posted @ 2025-10-16 11:32  BIxuan—玉寻  阅读(18)  评论(0)    收藏  举报