IDA*就是基于迭代深搜上的A*算法,最主要的就是在迭代深搜的过程中加了一个估价函数,关键还是这个估价函数的构造,ORZ,少了这个估价函数,对于这题目的话,直接TLE的说。
这题目的估价函数是这样的,根据目前的地图简单的判断一下至少还要转多少次吧。
这个估价函数“每次移动改变四个点的位置,即h()=(最少可能的横向或纵向不在位置上的点的个数+3)/4 )”,是参照大牛的。至于这么判断的,就要结合代码好好理解了……
至于迭代加深,在之前的题目已经接触过了
#include<iostream>
#include<algorithm>
using namespace std;
int map[5][5],step;
inline int check()
{
bool vis[5];
int cnt,temp=0,minn=20;
for(int i=0;i<4;i++)
{
cnt=4;
memset(vis,0,sizeof(vis));
for(int j=0;j<4;j++)
{
if(vis[map[i][j]])continue;
vis[map[i][j]]=true;
cnt--;
}
temp+=3-cnt;//通俗一点的说,3-cnt表示的是这一行或列有多少个数字是不应该出现的
}
if(temp<minn)
minn=temp;
temp=0;
for(int j=0;j<4;j++)
{
cnt=4;
memset(vis,0,sizeof(vis));
for(int i=0;i<4;i++)
{
if(vis[map[i][j]])continue;
vis[map[i][j]]=true;
cnt--;
}
temp+=3-cnt;
}
if(temp<minn)
minn=temp;
return minn;//最后的minn保存的是按行或列来转,最少有多少个位置是错的
}
void TurnL(int x)
{
int t=map[x][0];
for(int i=1;i<4;i++)
map[x][i-1]=map[x][i];
map[x][3]=t;
}
void TurnR(int x)
{
int t=map[x][3];
for(int i=2;i>=0;i--)
map[x][i+1]=map[x][i];
map[x][0]=t;
}
void TurnU(int x)
{
int t=map[0][x];
for(int i=1;i<4;i++)
map[i-1][x]=map[i][x];
map[3][x]=t;
}
void TurnD(int x)
{
int t=map[3][x];
for(int i=2;i>=0;i--)
map[i+1][x]=map[i][x];
map[0][x]=t;
}
bool dfs(int cnt)
{
int temp=check();
if(cnt==step && temp==0)
return true;
if(cnt+(temp+3)/4>step)//除以4 是最理想化的情况,转一次使四个数字回到正确的位置,+3就比较好理解了
return false;
for(int i=0;i<4;i++)
{
TurnL(i);
if(dfs(cnt+1))
return true;
TurnR(i);
TurnR(i);
if(dfs(cnt+1))
return true;
TurnL(i);
TurnU(i);
if(dfs(cnt+1))
return true;
TurnD(i);
TurnD(i);
if(dfs(cnt+1))
return true;
TurnU(i);
}
return false;
}
int main()
{
int cas;
scanf("%d",&cas);
while(cas--)
{
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
scanf("%d",&map[i][j]);
if(!check())
{
puts("0");
continue;
}
step=1;
while(true)
{
if(step>5)break;
if(dfs(0))
break;
step++;
}
if(step>5)puts("-1");
else printf("%d\n",step);
}
return 0;
}