题目大意:数字1,2,3都有八个,求出最少的旋转次数使得图形中间八个数相同。旋转规则:对于每一长行或每一长列,每次旋转就是将数据向头的位置移动一位,头上的数放置到尾部。若次数相同,则找出字典序最小旋转次序。
题目分析:IDA*,若当前在第cur层,中间八个数中1,2,3的个数分别为a,b,c。则d=8-max(a,b,c)便是达到目标还需要的理想次数,若cur+d>maxd,则剪枝。《入门经典》上提供了一种BFS的思路,分别以1,2,3为目标广搜3次,不过自己的码力还是太弱,并没有用那种方法AC。。。!!!
代码如下:
# include<iostream> # include<cstdio> # include<queue> # include<cstring> # include<algorithm> using namespace std; int a[24],d[8][7]={ {0,2,6,11,15,20,22}, {1,3,8,12,17,21,23}, {10,9,8,7,6,5,4}, {19,18,17,16,15,14,13}, {23,21,17,12,8,3,1}, {22,20,15,11,6,2,0}, {13,14,15,16,17,18,19}, {4,5,6,7,8,9,10}, }; int g[8]={6,7,8,11,12,15,16,17}; int ans; string ansp; bool dfs(int cur,int maxd,string path) { if(cur==maxd){ int ok=1; for(int i=1;i<8;++i) if(a[g[i]]!=a[g[i-1]]){ ok=0; break; } if(!ok) return false; ans=a[g[0]],ansp=path; return true; } int b[3]={0,0,0}; for(int i=0;i<8;++i) ++b[a[g[i]]-1]; int dd=8-max(max(b[0],b[1]),b[2]); if(cur+dd>maxd) return false; for(int i=0;i<8;++i){ int v=a[d[i][0]]; for(int j=0;j<6;++j) a[d[i][j]]=a[d[i][j+1]]; a[d[i][6]]=v; if(dfs(cur+1,maxd,path+char(i+'A'))) return true; v=a[d[i][6]]; for(int j=6;j>0;--j) a[d[i][j]]=a[d[i][j-1]]; a[d[i][0]]=v; } return false; } int main() { while(scanf("%d",&a[0])&&a[0]) { for(int i=1;i<24;++i) scanf("%d",a+i); ans=-1; for(int maxd=0;;++maxd){ if(dfs(0,maxd,"")){ if(maxd==0) printf("No moves needed "); else cout<<ansp<<endl; printf("%d ",ans); break; } } } return 0; }