HDU 2953 Rubiks Cube

二阶魔方旋转,数据比较大,而且六面均可旋转(与HDU3459不同),结束状态不确定(与HDU2691不同),status里面各种WA,TLE,MLE,只有一人AC,果断膜拜,然后标记为神题就没去看了,后来看了那人代码,方法比较巧妙,但也并不是什么高深难懂的算法,可以说是双广+预处理

对每个面标号一下,我们用数字表示小面,字母表示颜色,用[字母]表示大面,如下

00 01
02 03
04 05 06 07 08 09 10 11
12 13 14 15 16 17 18 19
20 21
22 23

OO
OO
RR GG BB WW
RR GG BB WW
YY
YY

[O]
[R][G][B][W]
[Y]
  
首先我们可以想到,一个面的顺时针旋转相当于他的相对面逆时针旋转,这样我们可以将六个面的旋转转化为三个面的旋转,比如说我们对于[R]面的顺时针旋转就相当于对[B]面的逆时针旋转,而且这样步数是不会增大的,而状态减少了许多。
 

然后我们去找魔方的特殊性,二阶魔方的24个面并不是独立的,从魔方结构就能看出一个二阶魔方是分为8个小块的,每个块三种颜色,比如说图中的(3,5,6)是在同一块上,(1,7,8)是在同一块上,这样我们根据他的特殊性从每一个块去分析

 
我们只做[R][G][O]面的正逆旋转,这样的话(17,18,22)这一块的是不会移动的,即[B][W][Y]这三个面的最终颜色是确定的,然后再去扩展,与B和W在同一块里的除了Y之外还有O,B和Y还有G,Y和W还有R。按照上面所说的:我们将要求的魔方中的17 18 22三面分别变为B W Y,然后根据每块的相连关系将另外三面都重新染色,这样我们就将每一个魔方都转化为最终状态都相同情况了
  
然后的做法就很简单了,我们可以从一个状态开始扩展做预处理,但是保存全部状态内存消耗太大,我们可以只预处理出7层情况(二阶魔方最多需要14步到达最终状态),然后对每一个魔方,将它进行重新染色后进行广搜,搜到一个已经预处理过的状态时就返回答案,答案为两边步数之和,这样这题就搞定了~~


  1 #include<cstdio>
2 #include<cstring>
3 #include<map>
4 #include<queue>
5 #include<cstdlib>
6 using namespace std;
7
8 int cvr[6][12]={
9 {4,12,13,5,3,2,11,19,20,21,14,6},
10 {12,13,5,4,11,19,20,21,14,6,3,2},
11 {7,6,14,15,1,3,5,13,21,23,16,8},
12 {6,14,15,7,5,13,21,23,16,8,1,3},
13 {1,0,2,3,8,9,10,11,4,5,6,7},
14 {0,2,3,1,10,11,4,5,6,7,8,9}};
15
16 int block[8][3]={
17 {3,5,6},{1,7,8},{0,9,10},{2,4,11},
18 {12,19,20},{13,14,21},{15,16,23},{17,18,22}};
19
20 struct S{
21 char s[30];
22
23 friend bool operator< (const S& a,const S& b){
24 return strcmp(a.s,b.s)<0;
25 }
26
27 void change(){
28 map<char,char> col;
29 map<char,bool> flag;
30 col[s[17]]='B'; flag[s[17]]=true;
31 col[s[18]]='W'; flag[s[18]]=true;
32 col[s[22]]='Y'; flag[s[22]]=true;
33 for(int i=0;i<7;i++){
34 int cnt=0,sum=0,has=3;
35 if(flag[s[block[i][0]]]){cnt++;sum+=col[s[block[i][0]]];has-=0;}
36 if(flag[s[block[i][1]]]){cnt++;sum+=col[s[block[i][1]]];has-=1;}
37 if(flag[s[block[i][2]]]){cnt++;sum+=col[s[block[i][2]]];has-=2;}
38 if(cnt!=2) continue;
39 if(sum=='B'+'W') col[s[block[i][has]]]='O';
40 if(sum=='B'+'Y') col[s[block[i][has]]]='G';
41 if(sum=='Y'+'W') col[s[block[i][has]]]='R';
42 }
43 for(int i=0;i<24;i++){
44 s[i]=col[s[i]];
45 }
46 }
47 }s;
48 map<S,int> step;
49
50 void in(char &c){
51 c=getchar();
52 while(c<=32) c=getchar();
53 }
54
55 void bfs0(){
56 strcpy(s.s,"OOOORRGGBBWWRRGGBBWWYYYY");
57 step.clear();
58 step[s]=-1;
59
60 queue<pair<S,int> > que;
61 que.push(make_pair(s,0));
62 while(!que.empty()){
63 S u=que.front().first;
64 int d=que.front().second;
65 que.pop();
66 for(int i=0;i<6;i++){
67 S v=u;
68 for(int j=0;j<12;j++){
69 v.s[cvr[i][j]]=u.s[cvr[i^1][j]];
70 }
71 if(step[v]) continue;
72 step[v]=d+1;
73 if(d<6){
74 que.push(make_pair(v,d+1));
75 }
76 }
77 }
78 }
79
80 map<S,bool> vis;
81 int bfs1(){
82 s.change();
83
84 if(step[s]){
85 if(step[s]==-1) return 0;
86 else return step[s];
87 }
88 vis.clear();
89 vis[s]=true;
90
91 queue<pair<S,int> > que;
92 que.push(make_pair(s,0));
93 while(!que.empty()){
94 S u=que.front().first;
95 int d=que.front().second;
96 que.pop();
97 for(int i=0;i<6;i++){
98 S v=u;
99 for(int j=0;j<12;j++){
100 v.s[cvr[i][j]]=u.s[cvr[i^1][j]];
101 }
102 if(vis[v]) continue;
103 vis[v]=true;
104 if(step[v]){
105 if(step[v]==-1) return d+1;
106 else return step[v]+d+1;
107 }
108 que.push(make_pair(v,d+1));
109 }
110 }
111 return -1;
112 }
113
114 int main(){
115 bfs0();
116
117 int t;
118 scanf("%d",&t);
119 while(t--){
120 for(int i=0;i<24;i++){
121 in(s.s[i]);
122 }
123
124 int ans=bfs1();
125 printf("%d\n",ans);
126 }
127 }

  

posted @ 2011-08-24 12:52  Amb@HDU  阅读(709)  评论(0编辑  收藏  举报