题目
小葱将买来的糖放进了冰箱冷藏,但是小葱想吃糖了,小葱希望把自己想吃的糖从冰箱里面拿出来。具体来说,在一张N N N 行N N N 列的方格图中,有若干颗糖,每颗糖都是横向或者竖向摆放的。对于一个横向摆放的糖,我们只能左右移动这颗糖(任意距离,但不能跨越其他糖),而对于一个竖向摆放的糖只能上下移动。我们的目标是把编号为1 1 1 的糖从冰箱移出去,而移出去的方法是让该糖果能够移动到方格图的右边界的位置(只有一号糖果能移出去,其他糖即使在边界也不能出去)。我们保证任何一颗糖果长度至少为2 2 2 ,并且1 1 1 号糖果一定横向放置。在糖果移动过程中不能穿越其他糖果,问在上述限制条件下小葱最少要移动多少次才能把1 1 1 号糖果移出冰箱。如果1 1 1 号糖果一开始就在右边界上请输出0 0 0 。
对于100 % 100\% 1 0 0 % 的数据,1 ≤ N ≤ 8 1\leq N\leq8 1 ≤ N ≤ 8 ,最多有13 13 1 3 种不同的糖果,答案不超过10 10 1 0 步。
题解
*搜索!*搜索!搜索!
每次移动任意糖任意步,把每一个状态存下来(为了判断是否重复),然后bfs
如何存呢?其实一个糖只需要记录它的一个坐标位置,另一个是不变的。
对于这些糖的坐标,可以用一个n n n 进制数来存,最多有13 13 1 3 种不同的糖果,所以n 13 − 1 n^{13} - 1 n 1 3 − 1
就够了,算一下,unsigned long long够了
注意
每次放入一个新的状态前先 检测要放入的这个状态是不是答案,否则有可能会被卡超时(因为这个调了2个小时QAQ)
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 #include <bits/stdc++.h> #define ull unsigned long long #define DOWN 1 #define RIGHT 0 using namespace std;const int N = 10 ;int a[N][N], n, typenum;const int M = 15 ;map<ull, int > step; queue<ull> qwq; int towards[M], pos[M], len[M], another_pos[M];void trans (ull state) { int cnt = typenum; while (cnt >= 1 ) { ull b = state % n; pos[cnt] = b; state /= n; if (towards[cnt] == DOWN) { for (int i = b;i <= b + len[cnt] - 1 ;i++) { a[i][another_pos[cnt]] = cnt; } } else { for (int i = b;i <= b + len[cnt] - 1 ;i++) { a[another_pos[cnt]][i] = cnt; } } cnt --; } } ull pack () { ull start = 0 ; for (int i = 1 ;i <= typenum;i++) { start = start * n + pos[i]; } return start; } int main () { freopen ("take.in" , "r" , stdin); freopen ("take.out" , "w" , stdout); ios::sync_with_stdio (0 ), cin.tie (0 ); cin >> n; for (int i = 1 ;i <= n;i++) { for (int j = 1 ;j <= n;j++) { cin >> a[i][j]; } } for (int i = 1 ;i <= n;i++) { for (int j = 1 ;j <= n;j++) { if (a[i][j] == 0 ) continue ; int cl = a[i][j]; if (a[i + 1 ][j] == cl) towards[cl] = DOWN; else towards[cl] = RIGHT; if (towards[cl] == DOWN) pos[cl] = i, another_pos[cl] = j; else pos[cl] = j, another_pos[cl] = i; int x = i, y = j; len[cl] = 0 ; while (x <= n && y <= n && a[x][y] == cl) { a[x][y] = 0 ; (towards[cl] == DOWN) ? (x ++) : (y++) ; len[cl] ++; } typenum = max (typenum, cl); } } ull start = 0 ; for (int i = 1 ;i <= typenum;i++) { start = start * n + pos[i]; } step[start] = 0 ; qwq.push (start); while (qwq.size ()) { ull t = qwq.front (); qwq.pop (); memset (a, 0 , sizeof a); trans (t); if (pos[1 ] + len[1 ] - 1 >= n) { cout << step[t] << endl; exit (0 ); } for (int i = 1 ;i <= typenum;i++) { if (towards[i] == DOWN) { for (int movement = 1 ;movement <= n;movement++) { if (a[pos[i] + len[i] - 1 + movement][another_pos[i]] != 0 || pos[i] + len[i] - 1 + movement > n) break ; pos[i] = pos[i] + movement; ull now = pack (); pos[i] -= movement; if (step[now] != 0 ) continue ; qwq.push (now), step[now] = step[t] + 1 ; if (i == 1 && pos[i] + len[i] - 1 + movement == n) { cout << step[now]; exit (0 ); } } for (int movement = -1 ;movement >= -n;movement--) { if (a[pos[i] + movement][another_pos[i]] != 0 || pos[i] + movement < 1 ) break ; pos[i] = pos[i] + movement; ull now = pack (); pos[i] -= movement; if (step[now] != 0 ) continue ; qwq.push (now), step[now] = step[t] + 1 ; if (i == 1 && pos[i] + len[i] - 1 + movement == n) { cout << step[now]; exit (0 ); } } } else { for (int movement = 1 ;movement <= n;movement++) { if (a[another_pos[i]][pos[i] + len[i] - 1 + movement] != 0 || pos[i] + len[i] - 1 + movement > n) break ; pos[i] = pos[i] + movement; ull now = pack (); pos[i] -= movement; if (step[now] != 0 ) continue ; qwq.push (now), step[now] = step[t] + 1 ; if (i == 1 && pos[i] + len[i] - 1 + movement == n) { cout << step[now]; exit (0 ); } } for (int movement = -1 ;movement >= -n;movement--) { if (a[another_pos[i]][pos[i] + movement] != 0 || pos[i] + movement < 1 ) break ; pos[i] = pos[i] + movement; ull now = pack (); pos[i] -= movement; if (step[now] != 0 ) continue ; qwq.push (now), step[now] = step[t] + 1 ; if (i == 1 && pos[i] + len[i] - 1 + movement == n) { cout << step[now]; exit (0 ); } } } } } return 0 ; }