题意: 题目给定一个有24个格子的棋盘,每个格子上有一个数字(1 or2 or3)。现在有ABCDEFGH 8种操作(即如图所示将对应的行/列向指定方向移动一格) , 求使得中间的8个格子的数字完全相同所需要的操作步数。
解法:IDA* 算法。。。dfs直接搜索直到找到答案为止 。 利用启发函数有一个剪枝 :当前情况下中间8个格子出现相同数字次数最多的次数x,如果x>dfs还能的层数,肯定不能达到满足条件的情况,不用再走了。(一次操作最多只能让x增加1) 。
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> using namespace std; int num[40] ; char ch[10] ={'A','B','C','D','E','F','G','H'} ; int mid[10]={7,8,9,12,13,16,17,18} ; int op[10]={5,4,7,6,1,0,3,2} ; //记录每种操作的逆操作 int ans,path[100]; int Mov[10][40]={ { 1,3,7,12,16,21,23 } , { 2,4,9,13,18,22,24 } , { 11,10,9,8,7,6,5 } , { 20,19,18,17,16,15,14}, { 24,22,18,13,9,4,2}, { 23,21,16,12,7,3,1}, { 14,15,16,17,18,19,20}, {5,6,7,8,9,10,11}, } ; int Equal() { int times[10]; memset(times ,0 ,sizeof times ) ; for(int i=0;i<8;i++){ times[num[mid[i]]]++; } if( times[1] == 8) ans =1 ; if( times[2] == 8) ans =2 ; if( times[3] == 8) ans =3 ; return 8 - max(times[1],max(times[2],times[3])); } void Move(int s){ int tem=num[Mov[s][0]] ; for(int i=0;i<6;i++){ num[Mov[s][i]] = num[Mov[s][(i+1)]] ; } num[Mov[s][6] ]= tem ; } int dfs(int dep) { if(dep <= 0) return 0; for(int i=0;i<8;i++){ Move(i) ; path[dep]=i; int h=Equal() ; if(!h) return 1; if(dep> h && dfs(dep-1)) return 1; Move(op[i]); } return 0; } void solve() { int dep = 1 ; while(!dfs(dep)){ //cout<<1<<endl; dep++; } for(int i=dep;i>=1;i--){ printf("%c",ch[path[i]]); } cout<<endl; cout<<ans<<endl; } int main() { int a; while(~scanf("%d",&a) && a!=0){ num[1] = a; for(int i=2;i<=24;i++){ scanf("%d",&num[i]); } if(!Equal()){ printf("No moves needed\n"); printf("%d\n",ans) ; } else{ solve() ; } } return 0; }