【HDOJ】4801 Pocket Cube 的几种解法和优化
1. 题目描述
给定一个$2 \times 2 \times 2$的魔方,当某个面上的4个小块颜色均相同时,称这个面为complete。求对这个魔方进行$n \in [1,7]$次旋转(沿某个面顺时针或者逆时针)的过程中,求complete的面总和的最大值。魔方及索引如下图所示:
2. 基本思路及代码
解法一(MLE):
刚读过题,觉得挺简单的,时限10000ms还挺长的。需要搞清楚沿着某个面旋转后矩阵的元素是如何变化的。
就想到可以进行状态压缩$6^24 < 2^63$,因此将cube表示的矩阵可以使用long long压缩状态,然后再带上已经旋转的次数作为key,记忆化搜索就好了。代码如下:
1 /* 4801 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque> 11 #include <bitset> 12 #include <algorithm> 13 #include <cstdio> 14 #include <cmath> 15 #include <ctime> 16 #include <cstring> 17 #include <climits> 18 #include <cctype> 19 #include <cassert> 20 #include <functional> 21 #include <iterator> 22 #include <iomanip> 23 using namespace std; 24 //#pragma comment(linker,"/STACK:102400000,1024000") 25 26 #define sti set<int> 27 #define stpii set<pair<int, int> > 28 #define mpii map<int,int> 29 #define vi vector<int> 30 #define pii pair<int,int> 31 #define vpii vector<pair<int,int> > 32 #define rep(i, a, n) for (int i=a;i<n;++i) 33 #define per(i, a, n) for (int i=n-1;i>=a;--i) 34 #define clr clear 35 #define pb push_back 36 #define mp make_pair 37 #define fir first 38 #define sec second 39 #define all(x) (x).begin(),(x).end() 40 #define SZ(x) ((int)(x).size()) 41 #define lson l, mid, rt<<1 42 #define rson mid+1, r, rt<<1|1 43 44 #define LL __int64 45 46 typedef struct { 47 int st, t; 48 } node_t; 49 50 map<pair<LL,int>, int> tb; 51 map<pair<LL,int>, int>::iterator iter; 52 LL mask[24]; 53 int a[24]; 54 int n; 55 int face[6][4] = { 56 {0, 1, 2, 3}, 57 {4, 5, 10, 11}, 58 {6, 7, 12, 13}, 59 {8, 9, 14, 15}, 60 {16, 17, 18, 19}, 61 {20, 21, 22, 23} 62 }; 63 64 int movf[6][12] = { 65 {0,1,3,2, 22,23,9,8,7,6,5,4}, 66 {18,19,17,16, 20,21,15,14,13,12,11,10,}, 67 {4,5,11,10, 0,2,6,12,16,18,20,22}, 68 {9,8,14,15, 1,3,7,13,17,19,21,23}, 69 {6,7,12,13, 2,3,8,14,17,16,11,5}, 70 {22,23,21,20, 0,1,9,15,19,18,10,4} 71 }; 72 int nxt[4]; 73 int unxt[4]; 74 75 void init() { 76 mask[0] = 3; 77 rep(i, 1, 24) 78 mask[i] = mask[i-1] << 2; 79 80 rep(i, 0, 4) { 81 nxt[i] = (i+1) % 4; 82 unxt[i] = (i-1+4)%4; 83 } 84 } 85 86 LL zip(int *a) { 87 LL ret = 0; 88 89 per(i, 0, 24) 90 ret = ret*6 + a[i]; 91 92 return ret; 93 } 94 95 void unzip(LL val, int *a) { 96 rep(i, 0, 24) { 97 a[i] = val % 6; 98 val /= 6; 99 } 100 } 101 102 int calc(LL st) { 103 static int b[24]; 104 int ret = 0; 105 unzip(st, b); 106 107 rep(i, 0, 6) { 108 ++ret; 109 rep(j, 1, 4) { 110 if (b[face[i][j]] != b[face[i][0]]) { 111 --ret; 112 break; 113 } 114 } 115 } 116 117 return ret; 118 } 119 120 LL move_clock(LL st, int id) { 121 static int b[24]; 122 static int c[24]; 123 int i, j, *mf = movf[id]; 124 125 unzip(st, b); 126 memcpy(c, b, sizeof(c)); 127 128 for (i=0; i<4; ++i) 129 c[mf[nxt[i]]] = b[mf[i]]; 130 for (i=0; i<4; ++i) { 131 c[mf[(nxt[i]<<1)+4]] = b[mf[(i<<1)+4]]; 132 c[mf[(nxt[i]<<1|1)+4]] = b[mf[(i<<1|1)+4]]; 133 } 134 135 return zip(c); 136 } 137 138 LL move_unclock(LL st, int id) { 139 static int b[24]; 140 static int c[24]; 141 int i, j, *mf = movf[id]; 142 143 unzip(st, b); 144 memcpy(c, b, sizeof(c)); 145 146 for (i=0; i<4; ++i) 147 c[mf[unxt[i]]] = b[mf[i]]; 148 for (i=0; i<4; ++i) { 149 c[mf[(unxt[i]<<1)+4]] = b[mf[(i<<1)+4]]; 150 c[mf[(unxt[i]<<1|1)+4]] = b[mf[(i<<1|1)+4]]; 151 } 152 153 return zip(c); 154 } 155 156 157 int dfs(LL st, int n) { 158 pair<LL,int> p = mp(st, n); 159 160 iter = tb.find(p); 161 if (iter != tb.end()) 162 return iter->sec; 163 164 int ret = 0; 165 166 ret = calc(st); 167 168 LL nst; 169 170 #ifndef ONLINE_JUDGE 171 int b[24]; 172 #endif 173 174 if (n) { 175 rep(i, 0, 6) { 176 nst = move_clock(st, i); 177 #ifndef ONLINE_JUDGE 178 unzip(nst, b); 179 rep(j, 0, 24) 180 printf("%d ", b[j]); 181 putchar('\n'); 182 #endif 183 ret = max(ret, dfs(nst, n-1)); 184 nst = move_unclock(st, i); 185 #ifndef ONLINE_JUDGE 186 unzip(nst, b); 187 rep(j, 0, 24) 188 printf("%d ", b[j]); 189 putchar('\n'); 190 #endif 191 ret = max(ret, dfs(nst, n-1)); 192 } 193 } 194 195 tb[p] = ret; 196 197 return ret; 198 } 199 200 void solve() { 201 LL st = zip(a); 202 int ans = 0; 203 204 // tb.clr(); 205 206 ans = dfs(st, n); 207 208 printf("%d\n", ans); 209 } 210 211 int main() { 212 ios::sync_with_stdio(false); 213 #ifndef ONLINE_JUDGE 214 freopen("data.in", "r", stdin); 215 freopen("data.out", "w", stdout); 216 #endif 217 218 init(); 219 while (scanf("%d", &n)!=EOF) { 220 rep(i, 0, 24) 221 scanf("%d", &a[i]); 222 solve(); 223 } 224 225 #ifndef ONLINE_JUDGE 226 printf("time = %d.\n", (int)clock()); 227 #endif 228 229 return 0; 230 }
交了一下,果断MLE了。分析为什么?显然状态太多了,因为同一个魔方因为摆放位置不同,表示的数组也不同,导致状态太多,记忆化搜索时存的东西太多。
解法二(TLE):
因为$n$很小,所以果断去掉了记忆化的map,抱着$n$很小但时限很长的侥幸心理,试试。
1 /* 4801 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque> 11 #include <bitset> 12 #include <algorithm> 13 #include <cstdio> 14 #include <cmath> 15 #include <ctime> 16 #include <cstring> 17 #include <climits> 18 #include <cctype> 19 #include <cassert> 20 #include <functional> 21 #include <iterator> 22 #include <iomanip> 23 using namespace std; 24 //#pragma comment(linker,"/STACK:102400000,1024000") 25 26 #define sti set<int> 27 #define stpii set<pair<int, int> > 28 #define mpii map<int,int> 29 #define vi vector<int> 30 #define pii pair<int,int> 31 #define vpii vector<pair<int,int> > 32 #define rep(i, a, n) for (int i=a;i<n;++i) 33 #define per(i, a, n) for (int i=n-1;i>=a;--i) 34 #define clr clear 35 #define pb push_back 36 #define mp make_pair 37 #define fir first 38 #define sec second 39 #define all(x) (x).begin(),(x).end() 40 #define SZ(x) ((int)(x).size()) 41 #define lson l, mid, rt<<1 42 #define rson mid+1, r, rt<<1|1 43 44 #define LL __int64 45 46 int a[24]; 47 int n; 48 int face[6][4] = { 49 {0, 1, 2, 3}, 50 {4, 5, 10, 11}, 51 {6, 7, 12, 13}, 52 {8, 9, 14, 15}, 53 {16, 17, 18, 19}, 54 {20, 21, 22, 23} 55 }; 56 57 int movf[6][12] = { 58 {0,1,3,2, 22,23,9,8,7,6,5,4}, 59 {18,19,17,16, 20,21,15,14,13,12,11,10,}, 60 {4,5,11,10, 0,2,6,12,16,18,20,22}, 61 {9,8,14,15, 1,3,7,13,17,19,21,23}, 62 {6,7,12,13, 2,3,8,14,17,16,11,5}, 63 {22,23,21,20, 0,1,9,15,19,18,10,4} 64 }; 65 int nxt[4]; 66 int unxt[4]; 67 68 void init() { 69 rep(i, 0, 4) { 70 nxt[i] = (i+1) % 4; 71 unxt[i] = (i-1+4)%4; 72 } 73 } 74 75 LL zip(int *a) { 76 LL ret = 0; 77 78 per(i, 0, 24) 79 ret = ret*6 + a[i]; 80 81 return ret; 82 } 83 84 void unzip(LL val, int *a) { 85 rep(i, 0, 24) { 86 a[i] = val % 6; 87 val /= 6; 88 } 89 } 90 91 int calc(LL st) { 92 static int b[24]; 93 int ret = 0; 94 unzip(st, b); 95 96 rep(i, 0, 6) { 97 ++ret; 98 rep(j, 1, 4) { 99 if (b[face[i][j]] != b[face[i][0]]) { 100 --ret; 101 break; 102 } 103 } 104 } 105 106 return ret; 107 } 108 109 LL move_clock(LL st, int id) { 110 static int b[24]; 111 static int c[24]; 112 int i, j, *mf = movf[id]; 113 114 unzip(st, b); 115 memcpy(c, b, sizeof(c)); 116 117 for (i=0; i<4; ++i) 118 c[mf[nxt[i]]] = b[mf[i]]; 119 for (i=0; i<4; ++i) { 120 c[mf[(nxt[i]<<1)+4]] = b[mf[(i<<1)+4]]; 121 c[mf[(nxt[i]<<1|1)+4]] = b[mf[(i<<1|1)+4]]; 122 } 123 124 return zip(c); 125 } 126 127 LL move_unclock(LL st, int id) { 128 static int b[24]; 129 static int c[24]; 130 int i, j, *mf = movf[id]; 131 132 unzip(st, b); 133 memcpy(c, b, sizeof(c)); 134 135 for (i=0; i<4; ++i) 136 c[mf[unxt[i]]] = b[mf[i]]; 137 for (i=0; i<4; ++i) { 138 c[mf[(unxt[i]<<1)+4]] = b[mf[(i<<1)+4]]; 139 c[mf[(unxt[i]<<1|1)+4]] = b[mf[(i<<1|1)+4]]; 140 } 141 142 return zip(c); 143 } 144 145 146 int dfs(LL st, int n) { 147 int ret = 0; 148 149 ret = calc(st); 150 151 LL nst; 152 153 if (n) { 154 rep(i, 0, 6) { 155 nst = move_clock(st, i); 156 ret = max(ret, dfs(nst, n-1)); 157 nst = move_unclock(st, i); 158 ret = max(ret, dfs(nst, n-1)); 159 } 160 } 161 162 return ret; 163 } 164 165 void solve() { 166 LL st = zip(a); 167 int ans = 0; 168 169 ans = dfs(st, n); 170 171 printf("%d\n", ans); 172 } 173 174 int main() { 175 ios::sync_with_stdio(false); 176 #ifndef ONLINE_JUDGE 177 freopen("data.in", "r", stdin); 178 freopen("data.out", "w", stdout); 179 #endif 180 181 init(); 182 while (scanf("%d", &n)!=EOF) { 183 rep(i, 0, 24) 184 scanf("%d", &a[i]); 185 solve(); 186 } 187 188 #ifndef ONLINE_JUDGE 189 printf("time = %d.\n", (int)clock()); 190 #endif 191 192 return 0; 193 }
果断TLE了。分析为什么?最坏情况下深搜的深度为7,每次深搜有12种旋转方式($6 \text{ faces } \times 2 \text{ directions }$)。
这棵搜索树的毛病太多了:结点太多($12^7 = 35831808$),存储消耗的也厉害。怎么办?
解法三(AC 717ms):
显然需要尽可能的减少旋转方式,观察6个面,两两相对。不妨令$F_a$与$F_b$相对,观察和想象可以发现对$F_a$进行顺时针旋转和对$F_b$进行逆时针旋转得到是相同配置的魔方。这样我们可以将旋转方式减少到6种,$6^7 = 279936$已经足够小了。这次果然AC,时间717ms,说明数据还是比较小的。
1 /* 4801 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque> 11 #include <bitset> 12 #include <algorithm> 13 #include <cstdio> 14 #include <cmath> 15 #include <ctime> 16 #include <cstring> 17 #include <climits> 18 #include <cctype> 19 #include <cassert> 20 #include <functional> 21 #include <iterator> 22 #include <iomanip> 23 using namespace std; 24 #pragma comment(linker,"/STACK:102400000,1024000") 25 26 #define sti set<int> 27 #define stpii set<pair<int, int> > 28 #define mpii map<int,int> 29 #define vi vector<int> 30 #define pii pair<int,int> 31 #define vpii vector<pair<int,int> > 32 #define rep(i, a, n) for (int i=a;i<n;++i) 33 #define per(i, a, n) for (int i=n-1;i>=a;--i) 34 #define clr clear 35 #define pb push_back 36 #define mp make_pair 37 #define fir first 38 #define sec second 39 #define all(x) (x).begin(),(x).end() 40 #define SZ(x) ((int)(x).size()) 41 #define lson l, mid, rt<<1 42 #define rson mid+1, r, rt<<1|1 43 44 #define LL __int64 45 46 int a[24]; 47 int n; 48 int face[6][4] = { 49 {0, 1, 2, 3}, 50 {4, 5, 10, 11}, 51 {6, 7, 12, 13}, 52 {8, 9, 14, 15}, 53 {16, 17, 18, 19}, 54 {20, 21, 22, 23} 55 }; 56 57 int movf[3][12] = { 58 {0,1,3,2, 22,23,9,8,7,6,5,4}, 59 // {18,19,17,16, 20,21,15,14,13,12,11,10,}, 60 {4,5,11,10, 0,2,6,12,16,18,20,22}, 61 // {9,8,14,15, 1,3,7,13,17,19,21,23}, 62 {6,7,13,12, 2,3,8,14,17,16,11,5} 63 // {22,23,21,20, 0,1,9,15,19,18,10,4}, 64 }; 65 int movp[6][24]; 66 int nxt[4]; 67 int unxt[4]; 68 int ans; 69 70 void init() { 71 rep(i, 0, 4) { 72 nxt[i] = (i+1) % 4; 73 unxt[i] = (i-1+4)%4; 74 } 75 76 int i, j, k; 77 for (k=0,j=0; k<3; ++k,j+=2) { 78 int *mf = movf[k]; 79 int *c = movp[j]; 80 for (i=0; i<24; ++i) c[i] = i; 81 for (i=0; i<4; ++i) 82 c[mf[nxt[i]]] = mf[i]; 83 for (i=0; i<4; ++i) { 84 c[mf[(nxt[i]<<1)+4]] = mf[(i<<1)+4]; 85 c[mf[(nxt[i]<<1|1)+4]] = mf[(i<<1|1)+4]; 86 } 87 88 c = movp[j+1]; 89 for (i=0; i<24; ++i) c[i] = i; 90 for (i=0; i<4; ++i) 91 c[mf[unxt[i]]] = mf[i]; 92 for (i=0; i<4; ++i) { 93 c[mf[(unxt[i]<<1)+4]] = mf[(i<<1)+4]; 94 c[mf[(unxt[i]<<1|1)+4]] = mf[(i<<1|1)+4]; 95 } 96 } 97 } 98 99 int calc(int *b) { 100 int ret = 0; 101 102 rep(i, 0, 6) { 103 ++ret; 104 rep(j, 1, 4) { 105 if (b[face[i][j]] != b[face[i][0]]) { 106 --ret; 107 break; 108 } 109 } 110 } 111 112 return ret; 113 } 114 115 inline void move(int *b, int *c, int id) { 116 int i; 117 118 for (i=0; i<24; ++i) c[i] = b[movp[id][i]]; 119 } 120 121 void dfs(int *a, int n) { 122 int b[24]; 123 124 ans = max(ans, calc(a)); 125 126 if (n) { 127 rep(i, 0, 6) { 128 move(a, b, i); 129 dfs(b, n-1); 130 } 131 } 132 } 133 134 void solve() { 135 ans = 0; 136 137 dfs(a, n); 138 139 printf("%d\n", ans); 140 } 141 142 int main() { 143 ios::sync_with_stdio(false); 144 #ifndef ONLINE_JUDGE 145 freopen("data.in", "r", stdin); 146 freopen("data.out", "w", stdout); 147 #endif 148 149 init(); 150 while (scanf("%d", &n)!=EOF) { 151 rep(i, 0, 24) 152 scanf("%d", &a[i]); 153 solve(); 154 } 155 156 #ifndef ONLINE_JUDGE 157 printf("time = %d.\n", (int)clock()); 158 #endif 159 160 return 0; 161 }
解法四(AC 265ms):
能不能再优化?为了优化这个深搜,显然要剪枝。基本思路是启发式函数或者剪掉重复状态。没想到太好的启发函数,因此思考能不能对已经出现的配置的魔方不再进行深搜(类似于方法一的记忆化搜索)。考虑对同一个面先顺时针旋转后立即进行逆时针旋转是没有意义的,因此这个可以剪枝。将717ms优化到265ms,效果还不错。
1 /* 4801 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque> 11 #include <bitset> 12 #include <algorithm> 13 #include <cstdio> 14 #include <cmath> 15 #include <ctime> 16 #include <cstring> 17 #include <climits> 18 #include <cctype> 19 #include <cassert> 20 #include <functional> 21 #include <iterator> 22 #include <iomanip> 23 using namespace std; 24 #pragma comment(linker,"/STACK:102400000,1024000") 25 26 #define sti set<int> 27 #define stpii set<pair<int, int> > 28 #define mpii map<int,int> 29 #define vi vector<int> 30 #define pii pair<int,int> 31 #define vpii vector<pair<int,int> > 32 #define rep(i, a, n) for (int i=a;i<n;++i) 33 #define per(i, a, n) for (int i=n-1;i>=a;--i) 34 #define clr clear 35 #define pb push_back 36 #define mp make_pair 37 #define fir first 38 #define sec second 39 #define all(x) (x).begin(),(x).end() 40 #define SZ(x) ((int)(x).size()) 41 #define lson l, mid, rt<<1 42 #define rson mid+1, r, rt<<1|1 43 44 #define LL __int64 45 46 int a[24]; 47 int n; 48 int face[6][4] = { 49 {0, 1, 2, 3}, 50 {4, 5, 10, 11}, 51 {6, 7, 12, 13}, 52 {8, 9, 14, 15}, 53 {16, 17, 18, 19}, 54 {20, 21, 22, 23} 55 }; 56 57 int movf[3][12] = { 58 {0,1,3,2, 22,23,9,8,7,6,5,4}, 59 // {18,19,17,16, 20,21,15,14,13,12,11,10,}, 60 {4,5,11,10, 0,2,6,12,16,18,20,22}, 61 // {9,8,14,15, 1,3,7,13,17,19,21,23}, 62 {6,7,13,12, 2,3,8,14,17,16,11,5} 63 // {22,23,21,20, 0,1,9,15,19,18,10,4}, 64 }; 65 int movp[6][24]; 66 int nxt[4]; 67 int unxt[4]; 68 int ans; 69 70 void init() { 71 rep(i, 0, 4) { 72 nxt[i] = (i+1) % 4; 73 unxt[i] = (i-1+4)%4; 74 } 75 76 int i, j, k; 77 for (k=0,j=0; k<3; ++k,j+=2) { 78 int *mf = movf[k]; 79 int *c = movp[j]; 80 for (i=0; i<24; ++i) c[i] = i; 81 for (i=0; i<4; ++i) 82 c[mf[nxt[i]]] = mf[i]; 83 for (i=0; i<4; ++i) { 84 c[mf[(nxt[i]<<1)+4]] = mf[(i<<1)+4]; 85 c[mf[(nxt[i]<<1|1)+4]] = mf[(i<<1|1)+4]; 86 } 87 88 c = movp[j+1]; 89 for (i=0; i<24; ++i) c[i] = i; 90 for (i=0; i<4; ++i) 91 c[mf[unxt[i]]] = mf[i]; 92 for (i=0; i<4; ++i) { 93 c[mf[(unxt[i]<<1)+4]] = mf[(i<<1)+4]; 94 c[mf[(unxt[i]<<1|1)+4]] = mf[(i<<1|1)+4]; 95 } 96 } 97 } 98 99 int calc(int *b) { 100 int ret = 0; 101 102 rep(i, 0, 6) { 103 ++ret; 104 rep(j, 1, 4) { 105 if (b[face[i][j]] != b[face[i][0]]) { 106 --ret; 107 break; 108 } 109 } 110 } 111 112 return ret; 113 } 114 115 inline void move(int *b, int *c, int id) { 116 int i; 117 118 for (i=0; i<24; ++i) c[i] = b[movp[id][i]]; 119 } 120 121 void dfs(int *a, int n, int pre) { 122 int b[24]; 123 124 ans = max(ans, calc(a)); 125 126 if (n) { 127 rep(i, 0, 6) { 128 if ((i^1) == pre) 129 continue; 130 move(a, b, i); 131 dfs(b, n-1, i); 132 } 133 } 134 } 135 136 void solve() { 137 ans = 0; 138 139 dfs(a, n, -1); 140 141 printf("%d\n", ans); 142 } 143 144 int main() { 145 ios::sync_with_stdio(false); 146 #ifndef ONLINE_JUDGE 147 freopen("data.in", "r", stdin); 148 freopen("data.out", "w", stdout); 149 #endif 150 151 init(); 152 while (scanf("%d", &n)!=EOF) { 153 rep(i, 0, 24) 154 scanf("%d", &a[i]); 155 solve(); 156 } 157 158 #ifndef ONLINE_JUDGE 159 printf("time = %d.\n", (int)clock()); 160 #endif 161 162 return 0; 163 }
解法五(AC 265ms):
还能不能继续剪枝?显然可以,对同一个面连续进行超过2次顺时针旋转或逆时针旋转没有任何意义,因为都可以通过更少次数的相反方向旋转实现。
然而,加上这个剪枝并没有什么提高,还能不能更快?
1 /* 4801 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque> 11 #include <bitset> 12 #include <algorithm> 13 #include <cstdio> 14 #include <cmath> 15 #include <ctime> 16 #include <cstring> 17 #include <climits> 18 #include <cctype> 19 #include <cassert> 20 #include <functional> 21 #include <iterator> 22 #include <iomanip> 23 using namespace std; 24 #pragma comment(linker,"/STACK:102400000,1024000") 25 26 #define sti set<int> 27 #define stpii set<pair<int, int> > 28 #define mpii map<int,int> 29 #define vi vector<int> 30 #define pii pair<int,int> 31 #define vpii vector<pair<int,int> > 32 #define rep(i, a, n) for (int i=a;i<n;++i) 33 #define per(i, a, n) for (int i=n-1;i>=a;--i) 34 #define clr clear 35 #define pb push_back 36 #define mp make_pair 37 #define fir first 38 #define sec second 39 #define all(x) (x).begin(),(x).end() 40 #define SZ(x) ((int)(x).size()) 41 #define lson l, mid, rt<<1 42 #define rson mid+1, r, rt<<1|1 43 44 #define LL __int64 45 46 int a[24]; 47 int n; 48 int face[6][4] = { 49 {0, 1, 2, 3}, 50 {4, 5, 10, 11}, 51 {6, 7, 12, 13}, 52 {8, 9, 14, 15}, 53 {16, 17, 18, 19}, 54 {20, 21, 22, 23} 55 }; 56 57 int movf[3][12] = { 58 {0,1,3,2, 22,23,9,8,7,6,5,4}, 59 {4,5,11,10, 0,2,6,12,16,18,20,22}, 60 {6,7,13,12, 2,3,8,14,17,16,11,5} 61 }; 62 int movp[6][24]; 63 int nxt[4]; 64 int unxt[4]; 65 int ans; 66 67 void init() { 68 rep(i, 0, 4) { 69 nxt[i] = (i+1) % 4; 70 unxt[i] = (i-1+4)%4; 71 } 72 73 int i, j, k; 74 for (k=0,j=0; k<3; ++k,j+=2) { 75 int *mf = movf[k]; 76 int *c = movp[j]; 77 for (i=0; i<24; ++i) c[i] = i; 78 for (i=0; i<4; ++i) 79 c[mf[nxt[i]]] = mf[i]; 80 for (i=0; i<4; ++i) { 81 c[mf[(nxt[i]<<1)+4]] = mf[(i<<1)+4]; 82 c[mf[(nxt[i]<<1|1)+4]] = mf[(i<<1|1)+4]; 83 } 84 85 c = movp[j+1]; 86 for (i=0; i<24; ++i) c[i] = i; 87 for (i=0; i<4; ++i) 88 c[mf[unxt[i]]] = mf[i]; 89 for (i=0; i<4; ++i) { 90 c[mf[(unxt[i]<<1)+4]] = mf[(i<<1)+4]; 91 c[mf[(unxt[i]<<1|1)+4]] = mf[(i<<1|1)+4]; 92 } 93 } 94 } 95 96 int calc(int *b) { 97 int ret = 0; 98 99 rep(i, 0, 6) { 100 ++ret; 101 rep(j, 1, 4) { 102 if (b[face[i][j]] != b[face[i][0]]) { 103 --ret; 104 break; 105 } 106 } 107 } 108 109 return ret; 110 } 111 112 inline void move(int *b, int *c, int id) { 113 int i; 114 115 for (i=0; i<24; ++i) c[i] = b[movp[id][i]]; 116 } 117 118 void dfs(int *a, int n, int pre, int deep) { 119 int b[24]; 120 121 ans = max(ans, calc(a)); 122 123 if (n) { 124 rep(i, 0, 6) { 125 if ((i^1) == pre) 126 continue; 127 if (i != pre) { 128 move(a, b, i); 129 dfs(b, n-1, i, 1); 130 } else if (deep < 2) { 131 move(a, b, i); 132 dfs(b, n-1, i, deep+1); 133 } 134 } 135 } 136 } 137 138 void solve() { 139 ans = 0; 140 141 dfs(a, n, -1, 0); 142 143 printf("%d\n", ans); 144 } 145 146 int main() { 147 ios::sync_with_stdio(false); 148 #ifndef ONLINE_JUDGE 149 freopen("data.in", "r", stdin); 150 freopen("data.out", "w", stdout); 151 #endif 152 153 init(); 154 while (scanf("%d", &n)!=EOF) { 155 rep(i, 0, 24) 156 scanf("%d", &a[i]); 157 solve(); 158 } 159 160 #ifndef ONLINE_JUDGE 161 printf("time = %d.\n", (int)clock()); 162 #endif 163 164 return 0; 165 }
解法六(AC 234ms):
将问题转化,即$n$次旋转可以想象为长度为$n$的$[0,5]$的任意排列,当然这个排列中有些是可以被剪枝的。比如,形如$*F_aF_aF_a*$,或者$*F_aF_b*$。然而,无论魔方初始的配置是什么样的,旋转就是数组中的某些元素交换位置,因此可以预处理进行$[0,7]$次旋转后,数组中元素位置的排列。这个预处理,直接深搜就好了。果然,略微有所优化。
1 /* 4801 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque> 11 #include <bitset> 12 #include <algorithm> 13 #include <cstdio> 14 #include <cmath> 15 #include <ctime> 16 #include <cstring> 17 #include <climits> 18 #include <cctype> 19 #include <cassert> 20 #include <functional> 21 #include <iterator> 22 #include <iomanip> 23 using namespace std; 24 #pragma comment(linker,"/STACK:102400000,1024000") 25 26 #define sti set<int> 27 #define stpii set<pair<int, int> > 28 #define mpii map<int,int> 29 #define vi vector<int> 30 #define pii pair<int,int> 31 #define vpii vector<pair<int,int> > 32 #define rep(i, a, n) for (int i=a;i<n;++i) 33 #define per(i, a, n) for (int i=n-1;i>=a;--i) 34 #define clr clear 35 #define pb push_back 36 #define mp make_pair 37 #define fir first 38 #define sec second 39 #define all(x) (x).begin(),(x).end() 40 #define SZ(x) ((int)(x).size()) 41 #define lson l, mid, rt<<1 42 #define rson mid+1, r, rt<<1|1 43 44 #define LL __int64 45 46 typedef struct { 47 char a[24]; 48 } node_t; 49 50 int a[24], b[24]; 51 int n; 52 int face[6][4] = { 53 {0, 1, 2, 3}, 54 {4, 5, 10, 11}, 55 {6, 7, 12, 13}, 56 {8, 9, 14, 15}, 57 {16, 17, 18, 19}, 58 {20, 21, 22, 23} 59 }; 60 61 int movf[3][12] = { 62 {0,1,3,2, 22,23,9,8,7,6,5,4}, 63 {4,5,11,10, 0,2,6,12,16,18,20,22}, 64 {6,7,13,12, 2,3,8,14,17,16,11,5} 65 }; 66 int movp[6][24]; 67 int nxt[4]; 68 int unxt[4]; 69 int ans; 70 vector<node_t> vc[8]; 71 72 void dfs(node_t nd, int step, int pre, int deep) { 73 vc[step].pb(nd); 74 75 node_t d; 76 77 if (step < 7) { 78 rep(i, 0, 6) { 79 if ((i^1) == pre) 80 continue; 81 if (i != pre) { 82 rep(j, 0, 24) d.a[j] = nd.a[movp[i][j]]; 83 dfs(d, step+1, i, 1); 84 } else if (deep < 2) { 85 rep(j, 0, 24) d.a[j] = nd.a[movp[i][j]]; 86 dfs(d, step+1, i, deep+1); 87 } 88 } 89 } 90 } 91 92 void init() { 93 rep(i, 0, 4) { 94 nxt[i] = (i+1) % 4; 95 unxt[i] = (i-1+4)%4; 96 } 97 98 int i, j, k; 99 for (k=0,j=0; k<3; ++k,j+=2) { 100 int *mf = movf[k]; 101 int *c = movp[j]; 102 for (i=0; i<24; ++i) c[i] = i; 103 for (i=0; i<4; ++i) 104 c[mf[nxt[i]]] = mf[i]; 105 for (i=0; i<4; ++i) { 106 c[mf[(nxt[i]<<1)+4]] = mf[(i<<1)+4]; 107 c[mf[(nxt[i]<<1|1)+4]] = mf[(i<<1|1)+4]; 108 } 109 110 c = movp[j+1]; 111 for (i=0; i<24; ++i) c[i] = i; 112 for (i=0; i<4; ++i) 113 c[mf[unxt[i]]] = mf[i]; 114 for (i=0; i<4; ++i) { 115 c[mf[(unxt[i]<<1)+4]] = mf[(i<<1)+4]; 116 c[mf[(unxt[i]<<1|1)+4]] = mf[(i<<1|1)+4]; 117 } 118 } 119 120 node_t nd; 121 rep(i, 0, 24) nd.a[i] = i; 122 dfs(nd, 0, -1, 0); 123 } 124 125 int calc(int *b) { 126 int ret = 0; 127 128 rep(i, 0, 6) { 129 ++ret; 130 rep(j, 1, 4) { 131 if (b[face[i][j]] != b[face[i][0]]) { 132 --ret; 133 break; 134 } 135 } 136 } 137 138 return ret; 139 } 140 141 void solve() { 142 ans = 0; 143 144 rep(i, 0, n+1) { 145 int sz = SZ(vc[i]); 146 rep(j, 0, sz) { 147 rep(k, 0, 24) 148 b[k] = a[vc[i][j].a[k]]; 149 150 ans = max(ans, calc(b)); 151 } 152 } 153 154 printf("%d\n", ans); 155 } 156 157 int main() { 158 ios::sync_with_stdio(false); 159 #ifndef ONLINE_JUDGE 160 freopen("data.in", "r", stdin); 161 freopen("data.out", "w", stdout); 162 #endif 163 164 init(); 165 while (scanf("%d", &n)!=EOF) { 166 rep(i, 0, 24) 167 scanf("%d", &a[i]); 168 solve(); 169 } 170 171 #ifndef ONLINE_JUDGE 172 printf("time = %d.\n", (int)clock()); 173 #endif 174 175 return 0; 176 }
解法七(AC 171ms):
能不能再快点儿?因为有了预处理,我可以将预处理的深搜变为宽搜,这也是碰到深搜实在没什么可剪枝的优化方式。同样,略微有所提高。
1 /* 4801 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque> 11 #include <bitset> 12 #include <algorithm> 13 #include <cstdio> 14 #include <cmath> 15 #include <ctime> 16 #include <cstring> 17 #include <climits> 18 #include <cctype> 19 #include <cassert> 20 #include <functional> 21 #include <iterator> 22 #include <iomanip> 23 using namespace std; 24 #pragma comment(linker,"/STACK:102400000,1024000") 25 26 #define sti set<int> 27 #define stpii set<pair<int, int> > 28 #define mpii map<int,int> 29 #define vi vector<int> 30 #define pii pair<int,int> 31 #define vpii vector<pair<int,int> > 32 #define rep(i, a, n) for (int i=a;i<n;++i) 33 #define per(i, a, n) for (int i=n-1;i>=a;--i) 34 #define clr clear 35 #define pb push_back 36 #define mp make_pair 37 #define fir first 38 #define sec second 39 #define all(x) (x).begin(),(x).end() 40 #define SZ(x) ((int)(x).size()) 41 #define lson l, mid, rt<<1 42 #define rson mid+1, r, rt<<1|1 43 44 #define LL __int64 45 46 typedef struct { 47 char a[24]; 48 } node_t; 49 50 typedef struct { 51 node_t p; 52 int pre, deep; 53 } node; 54 55 int a[24], b[24]; 56 int n; 57 int face[6][4] = { 58 {0, 1, 2, 3}, 59 {4, 5, 10, 11}, 60 {6, 7, 12, 13}, 61 {8, 9, 14, 15}, 62 {16, 17, 18, 19}, 63 {20, 21, 22, 23} 64 }; 65 66 int movf[3][12] = { 67 {0,1,3,2, 22,23,9,8,7,6,5,4}, 68 {4,5,11,10, 0,2,6,12,16,18,20,22}, 69 {6,7,13,12, 2,3,8,14,17,16,11,5} 70 }; 71 int movp[6][24]; 72 int nxt[4]; 73 int unxt[4]; 74 int ans; 75 vector<node_t> vc[8]; 76 77 void bfs(); 78 79 void init() { 80 rep(i, 0, 4) { 81 nxt[i] = (i+1) % 4; 82 unxt[i] = (i-1+4)%4; 83 } 84 85 int i, j, k; 86 for (k=0,j=0; k<3; ++k,j+=2) { 87 int *mf = movf[k]; 88 int *c = movp[j]; 89 for (i=0; i<24; ++i) c[i] = i; 90 for (i=0; i<4; ++i) 91 c[mf[nxt[i]]] = mf[i]; 92 for (i=0; i<4; ++i) { 93 c[mf[(nxt[i]<<1)+4]] = mf[(i<<1)+4]; 94 c[mf[(nxt[i]<<1|1)+4]] = mf[(i<<1|1)+4]; 95 } 96 97 c = movp[j+1]; 98 for (i=0; i<24; ++i) c[i] = i; 99 for (i=0; i<4; ++i) 100 c[mf[unxt[i]]] = mf[i]; 101 for (i=0; i<4; ++i) { 102 c[mf[(unxt[i]<<1)+4]] = mf[(i<<1)+4]; 103 c[mf[(unxt[i]<<1|1)+4]] = mf[(i<<1|1)+4]; 104 } 105 } 106 107 bfs(); 108 } 109 110 void bfs() { 111 queue<node> Q; 112 node nd, d; 113 int step = 0; 114 115 rep(i, 0, 24) nd.p.a[i] = i; 116 nd.pre = -1; 117 nd.deep = 0; 118 Q.push(nd); 119 vc[step].pb(nd.p); 120 121 while (1) { 122 int sz = SZ(Q); 123 if (sz==0 || ++step>7) 124 break; 125 while (sz--) { 126 nd = Q.front(); 127 Q.pop(); 128 rep(i, 0, 6) { 129 if ((i^1) == nd.pre) 130 continue; 131 if (i != nd.pre) { 132 rep(j, 0, 24) d.p.a[j] = nd.p.a[movp[i][j]]; 133 d.pre = i; 134 d.deep = 1; 135 vc[step].pb(d.p); 136 Q.push(d); 137 138 } else if (nd.deep < 2) { 139 rep(j, 0, 24) d.p.a[j] = nd.p.a[movp[i][j]]; 140 d.pre = i; 141 d.deep = 2; 142 vc[step].pb(d.p); 143 Q.push(d); 144 } 145 } 146 } 147 } 148 } 149 150 int calc(int *b) { 151 int ret = 0; 152 153 rep(i, 0, 6) { 154 ++ret; 155 rep(j, 1, 4) { 156 if (b[face[i][j]] != b[face[i][0]]) { 157 --ret; 158 break; 159 } 160 } 161 } 162 163 return ret; 164 } 165 166 void solve() { 167 ans = 0; 168 169 rep(i, 0, n+1) { 170 int sz = SZ(vc[i]); 171 rep(j, 0, sz) { 172 rep(k, 0, 24) 173 b[k] = a[vc[i][j].a[k]]; 174 175 ans = max(ans, calc(b)); 176 } 177 } 178 179 printf("%d\n", ans); 180 } 181 182 int main() { 183 ios::sync_with_stdio(false); 184 #ifndef ONLINE_JUDGE 185 freopen("data.in", "r", stdin); 186 freopen("data.out", "w", stdout); 187 #endif 188 189 init(); 190 while (scanf("%d", &n)!=EOF) { 191 rep(i, 0, 24) 192 scanf("%d", &a[i]); 193 solve(); 194 } 195 196 #ifndef ONLINE_JUDGE 197 printf("time = %d.\n", (int)clock()); 198 #endif 199 200 return 0; 201 }
解法八(MLE 109ms):
打表看了一下$[0,7]$共有$98797$种情况,能不能减少?倘若能够减少,也意味着存在着$n_i > n_j$并且进行$n_i$和$n_j$旋转有相同排列的情况,那么$n_i$其实已经不用考虑了。这个排列长度为24,那么怎么判定当前排列是否出现过,并且尽可能节省内存?显然trie树,trie树本来就源自"information retrieval",但是不幸的还是MLE了。
1 /* 4801 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque> 11 #include <bitset> 12 #include <algorithm> 13 #include <cstdio> 14 #include <cmath> 15 #include <ctime> 16 #include <cstring> 17 #include <climits> 18 #include <cctype> 19 #include <cassert> 20 #include <functional> 21 #include <iterator> 22 #include <iomanip> 23 using namespace std; 24 #pragma comment(linker,"/STACK:102400000,1024000") 25 26 #define sti set<int> 27 #define stpii set<pair<int, int> > 28 #define mpii map<int,int> 29 #define vi vector<int> 30 #define pii pair<int,int> 31 #define vpii vector<pair<int,int> > 32 #define rep(i, a, n) for (int i=a;i<n;++i) 33 #define per(i, a, n) for (int i=n-1;i>=a;--i) 34 #define clr clear 35 #define pb push_back 36 #define mp make_pair 37 #define fir first 38 #define sec second 39 #define all(x) (x).begin(),(x).end() 40 #define SZ(x) ((int)(x).size()) 41 #define lson l, mid, rt<<1 42 #define rson mid+1, r, rt<<1|1 43 44 #define LL __int64 45 46 typedef struct { 47 char a[24]; 48 } node_t; 49 50 typedef struct { 51 node_t p; 52 int pre, deep; 53 } node; 54 55 int a[24], b[24]; 56 int n; 57 int face[6][4] = { 58 {0, 1, 2, 3}, 59 {4, 5, 10, 11}, 60 {6, 7, 12, 13}, 61 {8, 9, 14, 15}, 62 {16, 17, 18, 19}, 63 {20, 21, 22, 23} 64 }; 65 66 int movf[3][12] = { 67 {0,1,3,2, 22,23,9,8,7,6,5,4}, 68 {4,5,11,10, 0,2,6,12,16,18,20,22}, 69 {6,7,13,12, 2,3,8,14,17,16,11,5} 70 }; 71 int movp[6][24]; 72 int nxt[4]; 73 int unxt[4]; 74 int ans; 75 vector<node_t> vc[8]; 76 77 void bfs(); 78 79 void init() { 80 rep(i, 0, 4) { 81 nxt[i] = (i+1) % 4; 82 unxt[i] = (i-1+4)%4; 83 } 84 85 int i, j, k; 86 for (k=0,j=0; k<3; ++k,j+=2) { 87 int *mf = movf[k]; 88 int *c = movp[j]; 89 for (i=0; i<24; ++i) c[i] = i; 90 for (i=0; i<4; ++i) 91 c[mf[nxt[i]]] = mf[i]; 92 for (i=0; i<4; ++i) { 93 c[mf[(nxt[i]<<1)+4]] = mf[(i<<1)+4]; 94 c[mf[(nxt[i]<<1|1)+4]] = mf[(i<<1|1)+4]; 95 } 96 97 c = movp[j+1]; 98 for (i=0; i<24; ++i) c[i] = i; 99 for (i=0; i<4; ++i) 100 c[mf[unxt[i]]] = mf[i]; 101 for (i=0; i<4; ++i) { 102 c[mf[(unxt[i]<<1)+4]] = mf[(i<<1)+4]; 103 c[mf[(unxt[i]<<1|1)+4]] = mf[(i<<1|1)+4]; 104 } 105 } 106 107 bfs(); 108 } 109 110 typedef struct trie_t { 111 static const int maxn = 825145; 112 static const int rt = 1; 113 int nxt[maxn][24]; 114 int l; 115 116 trie_t() { 117 l = 2; 118 } 119 120 inline int newNode() { 121 assert(l < maxn); 122 return l++; 123 } 124 125 bool Insert(char *s) { 126 int i = 0; 127 int p = rt; 128 bool ret = false; 129 130 while (i < 24) { 131 char& id = s[i++]; 132 if (!nxt[p][id]) { 133 nxt[p][id] = newNode(); 134 ret = true; 135 } 136 p = nxt[p][id]; 137 } 138 139 return ret; 140 } 141 142 } trie_t; 143 144 trie_t trie; 145 146 void bfs() { 147 queue<node> Q; 148 node nd, d; 149 int step = 0; 150 151 rep(i, 0, 24) nd.p.a[i] = i; 152 nd.pre = -1; 153 nd.deep = 0; 154 Q.push(nd); 155 trie.Insert(nd.p.a); 156 vc[step].pb(nd.p); 157 158 while (1) { 159 int sz = SZ(Q); 160 if (sz==0 || ++step>7) 161 break; 162 while (sz--) { 163 nd = Q.front(); 164 Q.pop(); 165 rep(i, 0, 6) { 166 if ((i^1) == nd.pre) 167 continue; 168 if (i != nd.pre) { 169 rep(j, 0, 24) d.p.a[j] = nd.p.a[movp[i][j]]; 170 d.pre = i; 171 d.deep = 1; 172 173 } else if (nd.deep < 2) { 174 rep(j, 0, 24) d.p.a[j] = nd.p.a[movp[i][j]]; 175 d.pre = i; 176 d.deep = 2; 177 } else { 178 continue; 179 } 180 181 if (trie.Insert(d.p.a)) { 182 vc[step].pb(d.p); 183 Q.push(d); 184 } 185 } 186 } 187 } 188 189 #ifndef ONLINE_JUDGE 190 rep(i, 0, 8) 191 printf("%d\n", SZ(vc[i])); 192 printf("l = %d\n", trie.l); 193 #endif 194 } 195 196 int calc(int *b) { 197 int ret = 0; 198 199 rep(i, 0, 6) { 200 ++ret; 201 rep(j, 1, 4) { 202 if (b[face[i][j]] != b[face[i][0]]) { 203 --ret; 204 break; 205 } 206 } 207 } 208 209 return ret; 210 } 211 212 void solve() { 213 ans = 0; 214 215 rep(i, 0, n+1) { 216 int sz = SZ(vc[i]); 217 rep(j, 0, sz) { 218 rep(k, 0, 24) 219 b[k] = a[vc[i][j].a[k]]; 220 221 ans = max(ans, calc(b)); 222 } 223 } 224 225 printf("%d\n", ans); 226 } 227 228 int main() { 229 ios::sync_with_stdio(false); 230 #ifndef ONLINE_JUDGE 231 freopen("data.in", "r", stdin); 232 freopen("data.out", "w", stdout); 233 #endif 234 235 init(); 236 while (scanf("%d", &n)!=EOF) { 237 rep(i, 0, 24) 238 scanf("%d", &a[i]); 239 solve(); 240 } 241 242 #ifndef ONLINE_JUDGE 243 printf("time = %d.\n", (int)clock()); 244 #endif 245 246 return 0; 247 }
解法九(AC G++93ms C++109ms):
还是上一个思路,能不能使用别的数据结构代替trie树?可以将长为24的排列想象成字符串,因此适用于字符串的算法都可以采用,所以果断试试哈希(可以与trie对拍一下所有排列)。LCP哈希可以过,ELFHash等都试了一下,过不了。这样,就将$98797$近乎减少了一半,最终仅$44971$种情况,时间上也提高了很多。
1 /* 4801 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque> 11 #include <bitset> 12 #include <algorithm> 13 #include <cstdio> 14 #include <cmath> 15 #include <ctime> 16 #include <cstring> 17 #include <climits> 18 #include <cctype> 19 #include <cassert> 20 #include <functional> 21 #include <iterator> 22 #include <iomanip> 23 using namespace std; 24 #pragma comment(linker,"/STACK:102400000,1024000") 25 26 #define sti set<int> 27 #define stpii set<pair<int, int> > 28 #define mpii map<int,int> 29 #define vi vector<int> 30 #define pii pair<int,int> 31 #define vpii vector<pair<int,int> > 32 #define rep(i, a, n) for (int i=a;i<n;++i) 33 #define per(i, a, n) for (int i=n-1;i>=a;--i) 34 #define clr clear 35 #define pb push_back 36 #define mp make_pair 37 #define fir first 38 #define sec second 39 #define all(x) (x).begin(),(x).end() 40 #define SZ(x) ((int)(x).size()) 41 #define lson l, mid, rt<<1 42 #define rson mid+1, r, rt<<1|1 43 44 #define LL __int64 45 #define ULL unsigned __int64 46 47 typedef struct { 48 char a[24]; 49 } node_t; 50 51 typedef struct { 52 node_t p; 53 int pre, deep; 54 } node; 55 56 int a[24], b[24]; 57 int n; 58 int face[6][4] = { 59 {0, 1, 2, 3}, 60 {4, 5, 10, 11}, 61 {6, 7, 12, 13}, 62 {8, 9, 14, 15}, 63 {16, 17, 18, 19}, 64 {20, 21, 22, 23} 65 }; 66 67 int movf[3][12] = { 68 {0,1,3,2, 22,23,9,8,7,6,5,4}, 69 {4,5,11,10, 0,2,6,12,16,18,20,22}, 70 {6,7,13,12, 2,3,8,14,17,16,11,5} 71 }; 72 int movp[6][24]; 73 int nxt[4]; 74 int unxt[4]; 75 int ans; 76 vector<node_t> vc[8]; 77 78 void bfs(); 79 80 void init() { 81 rep(i, 0, 4) { 82 nxt[i] = (i+1) % 4; 83 unxt[i] = (i-1+4)%4; 84 } 85 86 int i, j, k; 87 for (k=0,j=0; k<3; ++k,j+=2) { 88 int *mf = movf[k]; 89 int *c = movp[j]; 90 for (i=0; i<24; ++i) c[i] = i; 91 for (i=0; i<4; ++i) 92 c[mf[nxt[i]]] = mf[i]; 93 for (i=0; i<4; ++i) { 94 c[mf[(nxt[i]<<1)+4]] = mf[(i<<1)+4]; 95 c[mf[(nxt[i]<<1|1)+4]] = mf[(i<<1|1)+4]; 96 } 97 98 c = movp[j+1]; 99 for (i=0; i<24; ++i) c[i] = i; 100 for (i=0; i<4; ++i) 101 c[mf[unxt[i]]] = mf[i]; 102 for (i=0; i<4; ++i) { 103 c[mf[(unxt[i]<<1)+4]] = mf[(i<<1)+4]; 104 c[mf[(unxt[i]<<1|1)+4]] = mf[(i<<1|1)+4]; 105 } 106 } 107 108 bfs(); 109 } 110 111 typedef struct Hash { 112 static const int MOD = 754283; 113 set<ULL> st; 114 115 void clear() { 116 st.clr(); 117 } 118 119 ULL HashCode(const char *s) { 120 ULL ret = 0; 121 122 rep(i, 0, 24) 123 ret = ret * MOD + s[i]; 124 125 return ret; 126 } 127 128 bool find(const node_t& p) { 129 ULL h = HashCode(p.a); 130 if (st.find(h) == st.end()) { 131 st.insert(h); 132 return false; 133 } else { 134 return true; 135 } 136 } 137 138 } Hash; 139 140 Hash tb; 141 142 void bfs() { 143 queue<node> Q; 144 node nd, d; 145 int step = 0; 146 147 rep(i, 0, 24) nd.p.a[i] = i; 148 nd.pre = -1; 149 nd.deep = 0; 150 Q.push(nd); 151 152 tb.clr(); 153 tb.find(nd.p); 154 vc[step].pb(nd.p); 155 156 while (1) { 157 int sz = SZ(Q); 158 if (sz==0 || ++step>7) 159 break; 160 while (sz--) { 161 nd = Q.front(); 162 Q.pop(); 163 rep(i, 0, 6) { 164 if ((i^1) == nd.pre) 165 continue; 166 if (i != nd.pre) { 167 rep(j, 0, 24) d.p.a[j] = nd.p.a[movp[i][j]]; 168 d.pre = i; 169 d.deep = 1; 170 171 } else if (nd.deep < 2) { 172 rep(j, 0, 24) d.p.a[j] = nd.p.a[movp[i][j]]; 173 d.pre = i; 174 d.deep = 2; 175 } else { 176 continue; 177 } 178 179 if (!tb.find(d.p)) { 180 vc[step].pb(d.p); 181 Q.push(d); 182 } 183 } 184 } 185 } 186 } 187 188 int calc(int *b) { 189 int ret = 0; 190 191 rep(i, 0, 6) { 192 ++ret; 193 rep(j, 1, 4) { 194 if (b[face[i][j]] != b[face[i][0]]) { 195 --ret; 196 break; 197 } 198 } 199 } 200 201 return ret; 202 } 203 204 void solve() { 205 ans = 0; 206 207 rep(i, 0, n+1) { 208 int sz = SZ(vc[i]); 209 rep(j, 0, sz) { 210 rep(k, 0, 24) 211 b[k] = a[vc[i][j].a[k]]; 212 213 ans = max(ans, calc(b)); 214 } 215 } 216 217 printf("%d\n", ans); 218 } 219 220 int main() { 221 ios::sync_with_stdio(false); 222 #ifndef ONLINE_JUDGE 223 freopen("data.in", "r", stdin); 224 freopen("data.out", "w", stdout); 225 #endif 226 227 init(); 228 while (scanf("%d", &n)!=EOF) { 229 rep(i, 0, 24) 230 scanf("%d", &a[i]); 231 solve(); 232 } 233 234 #ifndef ONLINE_JUDGE 235 printf("time = %d.\n", (int)clock()); 236 #endif 237 238 return 0; 239 }
93ms就是目前最快的了,因为耗内存,故排第4。后面又尝试了一下写了个内存池代替vector,但是效果并不明显。
这个题目是13年regional的题目,虽然不是特别难,但是可以看到结合多种算法不断进行优化这个过程很重要。
最开始学习算法的时候,基本上没什么思路,很多dp、二分都不会写。碰到TLE基本就要看题解了,现在逐渐可以自己想思路,找优化方式,我觉得这是一个显著的进步,这也是一种提高的方式。我认为算法的学习没什么捷径,深入了解算法的基本思路和证明过程,以及如何对基本算法进行提升很重要。