分析:IDA*解决,借鉴大牛的启发式函数h(): 可以考虑把每一行上的数转化成相同的,或者把每一列上的数字转化成相同的,二者取最小值。
例如:
1 1 3 2
2 4 4 2
3 3 1 4
1 2 3 4
把这个矩阵转化成行合法矩阵需要的操作:第一行至少要2次,第二行也是2次, 第三行是2次,第四行是3次, 所以把矩阵转化成行相同至少要3次。
#include<iostream>
using namespace std;
int map[5][5];
int deep;
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
bool check() //检查是否是合法状态
{
int i,j;
if(map[1][1]!=map[1][2])
{
for(i=1;i<=4;i++)
for(j=1;j<=4;j++)
if(map[j][i]!=map[i][i])
return false;
}
else
{
for(i=1;i<=4;i++)
for(j=1;j<=4;j++)
if(map[i][j]!=map[i][i])
return false;
}
return true;
}
int get_h() //IDA*的估价函数,获取每行或每列不在合法位置的数量
{
int r=0,c=0,i,j;
for(i=1;i<=4;i++) //每行
{
int ans=0;
int h[5]={0};
for(j=1;j<=4;j++) h[map[i][j]]++;
for(j=1;j<=4;j++)ans=max(ans,h[j]);
r=max(4-ans,r);
}
for(j=1;j<=4;j++) //每列
{
int ans=0;
int h[5]={0};
for(i=1;i<=4;i++) h[map[i][j]]++;
for(i=1;i<=4;i++)ans=max(ans,h[i]);
c=max(4-ans,c);
}
return min(r,c);
}
void mov_l(int i)
{
int j,t;
t=map[i][1];
for(j=2;j<=4;j++)
map[i][j-1]=map[i][j];
map[i][4]=t;
}
void mov_r(int i)
{
int j,t;
t=map[i][4];
for(j=4;j>=2;j--)
map[i][j]=map[i][j-1];
map[i][1]=t;
}
void mov_u(int j)
{
int i,t;
t=map[1][j];
for(i=2;i<=4;i++)
map[i-1][j]=map[i][j];
map[4][j]=t;
}
void mov_d(int j)
{
int i,t;
t=map[4][j];
for(i=4;i>=2;i--)
map[i][j]=map[i-1][j];
map[1][j]=t;
}
bool IDA_Star(int step)
{
int i;
if(step==deep)
return check();
if(step+get_h()>deep) //估价函数剪枝
return false;
for(i=1;i<=4;i++) //每行
{
mov_l(i);
if(IDA_Star(step+1))
return true;
mov_r(i); //恢复
mov_r(i);
if(IDA_Star(step+1))
return true;
mov_l(i); //恢复
}
for(i=1;i<=4;i++) //每列
{
mov_u(i);
if(IDA_Star(step+1))
return true;
mov_d(i); //恢复
mov_d(i);
if(IDA_Star(step+1))
return true;
mov_u(i); //恢复
}
return false;
}
int main()
{
int t,i,j;
cin>>t;
while(t--)
{
for(i=1;i<=4;i++)
for(j=1;j<=4;j++)
cin>>map[i][j];
if(check()) //判断开始是否合法
{
cout<<"0"<<endl;
continue;
}
deep=1;
while(deep<=5)
{
if(IDA_Star(0))
break;
deep++;
}
if(deep<=5)
cout<<deep<<endl;
else
cout<<"-1"<<endl;
}
return 0;
}原文地址:http://blog.csdn.net/a809146548/article/details/46316209