1. 程式人生 > 實用技巧 >IDA* (洛谷 P2324 [SCOI2005]騎士精神)

IDA* (洛谷 P2324 [SCOI2005]騎士精神)

傳送門:https://www.luogu.com.cn/problem/P2324

題目大意


前置知識

迭代加深

  • 每次搜尋開始時設定一個最大的搜尋深度,使得搜尋樹的深度不超過限定的這個數

    一般在具有步數限定的情況下,或者搜尋樹深度較大,但是搜尋所需的答案在較淺深度時使用

    (類似於BFS)

估值函式

  • 對於一步搜尋來說,可以對當前的搜尋節點設定一個估價,以預計它未來的實際代價,適時排除非最優情況,從而達到有效的正確剪枝

    設:\(g(n)\) 為當前的代價,\(h(n)\) 為未來預估的最優化代價,則 \(f(n)\) 代表的估值函式為:\(f(n) = g(n) + h(n)\)

ps

  • \(A*\)
    是對廣度優先搜尋結合估價函式的優化

  • \(IDA*\) 是結合迭代加深,對深度優先搜尋的優化

Solution

  • 設定估價函式:最有情況下,交換黑色棋子與白色棋子的最有情況就是直接通過一步移動到空格子上,然後互換即可,那麼顯然,與目標格子顏色位置不相符的格子的數量即為該估價函式的值

  • 結合迭代加深的方法直接進行深度優先搜尋即可

Code

#include<iostream>
#include<cstdio>
#include<math.h>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;

const ll maxn=10;
ll t,n,sx,sy,ans,flag,kkk;
ll go[10][2]={{0,0},{2,1},{1,2},{2,-1},{1,-2},{-1,-2},{-2,-1},{-2,1},{-1,2}};
ll goal[10][10]={\\最終結果圖,進行快速比較
	{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}
};
char a[maxn][maxn];
ll b[maxn][maxn];

inline ll gu()\\估價函式
{
	register ll ret=0;
	for(int i=1;i<=5;i++)
	{
		for(int j=1;j<=5;j++)
		{
			if(b[i][j]!=goal[i][j]) ret++;
		}
	}
	return ret;	
}

inline void dfs(ll step,ll x,ll y,ll maxx)
{
	if(step==maxx)
	{
		if(gu()==0) flag=1;
		return ;
	}
	for(int i=1;i<=8;i++)
	{
		ll tx=x+go[i][0];
		ll ty=y+go[i][1];
		if(tx<1||tx>5||ty<1||ty>5) continue;
		swap(b[x][y],b[tx][ty]);
		if(gu()+step<=maxx) dfs(step+1,tx,ty,maxx);
		swap(b[x][y],b[tx][ty]);
	}
}

int main(void)
{
	scanf("%lld",&t);
	while(t--)
	{
		flag=0;
		kkk=0;
		for(int i=1;i<=5;i++)
		{
			for(int j=1;j<=5;j++)
			{
				cin>>a[i][j];
				if(a[i][j]=='*')
				{
					b[i][j]=2;
					sx=i,sy=j;
				}
				else b[i][j]=a[i][j]-'0';
			}
		}
		
		for(int i=1;i<=15;i++)//迭代加深,限制搜尋步數
		{
			dfs(0,sx,sy,i);
			if(flag==1)
			{
				printf("%lld\n",i);
				kkk=1;
				break;
			}
		}
		if(kkk==0) printf("-1\n");
	}
	
	return 0;
}