IDA* 算法

IDA*算法是在A*算法的迭代加深

A*算法主要用在bfs中,IDA*算法主要用在dfs中

先来看一道IDA*的例题

IDA* 算法_第1张图片

IDA* 算法_第2张图片

 前置知识1:迭代加深

定义: 每次限定一个maxdep最大深度,使搜索树的深度不超过maxdep

for(int maxdep=1;maxdep<=题目中给的最大步数;maxdep++){
	dfs(0,maxdep);//0为出入函数中当前步数,maxdep为传入的最大深度。
	if(success)break;//如果搜索成功则会在dfs函数中将success赋值为1。
}

使用范围:

1.在有一定的限制条件时使用(例如本题中“如果能在15步以内(包括15步)到达目标状态,则输出步数,否则输出−1。“)。

2.题目中说输出所以解中的任何一组解。

为什么能够降低时间复杂度:

我们可能会在一个没有解(或解很深的地方无限递归然而题目中要求输出任何的一组解),所以我们限制一个深度,让它去遍历更多的分支,去更广泛地求解,(其实和BFS有异曲同工之妙)。


前置知识2:估价函数

定义:f(n)=g(n)+h(n)

其中f(n)是节点的估价函数,g(n)是现在的实际步数,h(n)是对未来步数的最完美估价(“完美”的意思是可能你现实也可能不会实现,但你还要拿最优的步数去把h(n)算出来。

void dfs(int dep,int maxdep){
    if(evaluate()+dep>maxdep)return;
    //evaluate函数为对未来估价的函数,若未来估价加实际步数>迭代加深的深度则return。
    if(!evaluate){
        success=1;
        printf("%d\n",dep);
        return;
    }
    ......
}

前置知识3:A*和IDA*的区别

A∗是用于对BFS的优化;

IDA*是对结合迭代加深的DFS 的优化。

本质上只是在BFS和DFS上加上了一个估价函数。

何时使用因题而定。

现在就是要想一个比较好的估价函数(若估价函数不好的话,优化效率就并不高,例如若估价函数一直为0,那就是爆搜)。


然后来看这道题

我们可以想一下,每次空白格子和黑白棋子交换,最优的情况就是每次都把黑白棋子移动到目标格子。

所以评估函数:

const int goal[7][7] = {
	{0,0,0,0,0,0},
	{0,1,1,1,1,1},
	{0,0,1,1,1,1},
	{0,0,0,2,1,1},
	{0,0,0,0,0,1},
	{0,0,0,0,0,0},
};
int evaluate(){
	int cnt=0;
	for(register int i(1) ; i<=5 ; i=-~i){
		for(register int j(1) ; j<=5 ; j=-~j){
			if(mp[i][j] != goal[i][j]) cnt++; //如果这两个点不相同
		}
	}
	return cnt; //返回最少理想情况下需要的次数
} 

然后这道题就是普通的爆搜了

#include
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch == '-') f=-1 ; ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48) ; ch=getchar();}
	return x*f;
}
const int M = 10;
const int dx[] = {1,1,-1,-1,2,2,-2,-2};
const int dy[] = {2,-2,2,-2,1,-1,1,-1};
int mp[M][M];
int T;
int n,m,success,sx,sy,flag;
const int goal[7][7] = {
	{0,0,0,0,0,0},
	{0,1,1,1,1,1},
	{0,0,1,1,1,1},
	{0,0,0,2,1,1},
	{0,0,0,0,0,1},
	{0,0,0,0,0,0},
};
int evaluate(){
	int cnt=0;
	for(register int i(1) ; i<=5 ; i=-~i){
		for(register int j(1) ; j<=5 ; j=-~j){
			if(mp[i][j] != goal[i][j]) cnt++;
		}
	}
	return cnt;
}
int pd(int x,int y){
	if(x<1||x>5||y<1||y>5) return 0;
	return 1;
}
void A_star(int dep,int x,int y,int maxdep){
	if(dep == maxdep){
		if(!evaluate()) success=1; //表示正好完全匹配
		return;
	}
	for(register int i(0) ; i<8 ; i=-~i){
		int xx = x + dx[i];
		int yy = y + dy[i]; //8个方向
		if(!pd(xx,yy)) continue; //不能走就跳过
		swap(mp[x][y],mp[xx][yy]); //把两个点的颜色交换
		int eva = evaluate(); //理想情况下的最少步数
		if(eva + dep <= maxdep) A_star(dep+1,xx,yy,maxdep); //如果有可能的话,接着往下搜
		swap(mp[x][y],mp[xx][yy]); //别忘了回溯
	}
}
signed main(){
	T=read();
	while(T--){
		success=0;
		flag=0; //别忘了先清零
		for(register int i(1) ; i<=5 ; i=-~i){
			for(register int j(1) ; j<=5 ; j=-~j){
				char ch;
				cin >> ch;
				if(ch == '*') mp[i][j] = 2,sx=i,sy=j; //这道题枚举那个空白好,因为次数少
				else mp[i][j] = ch-'0';
			}
		}
		if(!evaluate()) {printf("0\n");continue;}
		for(register int maxdep(1) ; maxdep<=15 ; maxdep=-~maxdep){ //限制最多次数
			A_star(0,sx,sy,maxdep);
			if(success) {printf("%d\n",maxdep);flag=1;break;} //如果能匹配
		}
		if(!flag) printf("-1\n"); //不能匹配
	}
	return 0;
}

你可能感兴趣的:(模板总结,学习笔记,算法)