HDU4801·二阶魔方
题意:给定二阶魔方初始状态,问N(1 <= N <= 7)步旋转操作以内最多能使几个面相同。
dfs搜索+剪枝。
魔方的每个旋转操作即对应于一个置换操作。又因为相对运动,上层左旋一次和下层右旋一次等价,故可分为6类操作。上层顺、逆时针旋转,左层顺、逆时针旋转,前层顺、逆时针旋转。这样每次操作有6种选择。
剪枝一:考虑旋转操作一次后,第二次不应进行逆操作回到旋转前状态。实现的时候将每种操作分别置为0、 1, 2、 3, 4、 5,操作1^操作2 = 1则说明两操作互为逆操作。
剪枝二:当有6个面相同时就停止搜索。
剪枝三:每个操作最多连续操作2次。(下述代码未实现该剪枝)
1 #include <bits/stdc++.h> 2 using namespace std; 3 int a[8][24], ans, n; 4 int turn[6][24] = { 5 {0,1,8,14,4,3,7,13,17,9,10,2,6,12,16,15,5,11,18,19,20,21,22,23}, 6 {0,1,11,5,4,16,12,6,2,9,10,17,13,7,3,15,14,8,18,19,20,21,22,23}, 7 8 {1,3,0,2,23,22,4,5,6,7,10,11,12,13,14,15,16,17,18,19,20,21,9,8}, 9 {2,0,3,1,6,7,8,9,23,22,10,11,12,13,14,15,16,17,18,19,20,21,5,4}, 10 11 {6,1,12,3,5,11,16,7,8,9,4,10,18,13,14,15,20,17,22,19,0,21,2,23}, 12 {20,1,22,3,10,4,0,7,8,9,11,5,2,13,14,15,6,17,12,19,16,21,18,23}, 13 }; 14 void debug(int a[], int p, int t){ 15 if(t == 0) return ; 16 int b[24]; 17 for(int i = 0; i < 24; i++){ 18 b[i] = a[ turn[p][i] ]; 19 printf("%d ", b[i]); 20 } 21 puts(""); 22 23 debug(b, p, t-1); 24 } 25 void dfs(int d, int pre){ 26 if(ans >= 6||d > n) return ; 27 if(d) for(int j = 0; j < 24; j++) 28 a[d][j] = a[d-1][ turn[pre][j] ]; 29 int now = (a[d][0] == a[d][1]&&a[d][1] == a[d][2]&&a[d][2] == a[d][3]) + 30 (a[d][4] == a[d][5]&&a[d][5] == a[d][10]&&a[d][10] == a[d][11])+ 31 (a[d][6] == a[d][7]&&a[d][7] == a[d][12]&&a[d][12] == a[d][13])+ 32 (a[d][8] == a[d][9]&&a[d][9] == a[d][14]&&a[d][14] == a[d][15])+ 33 (a[d][16] == a[d][17]&&a[d][17] == a[d][18]&&a[d][18] == a[d][19])+ 34 (a[d][20] == a[d][21]&&a[d][21] == a[d][22]&&a[d][22] == a[d][23]); 35 ans = max(ans, now); 36 for(int i = 0; i < 6; i++) 37 if( (i^pre) != 1) dfs(d+1, i); 38 } 39 int main(){ 40 while(~scanf("%d", &n)){ 41 for(int i = 0; i < 24; i++) 42 scanf("%d", &a[0][i]); 43 ans = 0; 44 dfs(0, -1); 45 cout<<ans<<endl; 46 } 47 return 0; 48 }
诸神对凡人心生艳羡,厌倦天堂。