分析: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