1108 字
6 分钟
小葱拿糖
题目
小葱将买来的糖放进了冰箱冷藏,但是小葱想吃糖了,小葱希望把自己想吃的糖从冰箱里面拿出来。具体来说,在一张行列的方格图中,有若干颗糖,每颗糖都是横向或者竖向摆放的。对于一个横向摆放的糖,我们只能左右移动这颗糖(任意距离,但不能跨越其他糖),而对于一个竖向摆放的糖只能上下移动。我们的目标是把编号为的糖从冰箱移出去,而移出去的方法是让该糖果能够移动到方格图的右边界的位置(只有一号糖果能移出去,其他糖即使在边界也不能出去)。我们保证任何一颗糖果长度至少为,并且号糖果一定横向放置。在糖果移动过程中不能穿越其他糖果,问在上述限制条件下小葱最少要移动多少次才能把号糖果移出冰箱。如果号糖果一开始就在右边界上请输出。
对于的数据,,最多有种不同的糖果,答案不超过步。
题解
*搜索!*搜索!搜索!
每次移动任意糖任意步,把每一个状态存下来(为了判断是否重复),然后bfs
如何存呢?其实一个糖只需要记录它的一个坐标位置,另一个是不变的。
对于这些糖的坐标,可以用一个进制数来存,最多有 种不同的糖果,所以 就够了,算一下,unsigned long long够了
注意
每次放入一个新的状态前先检测要放入的这个状态是不是答案,否则有可能会被卡超时(因为这个调了2个小时QAQ)
代码
#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压ullmap<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) {// cout << cnt << "点 DOWN" << endl; for(int i = b;i <= b + len[cnt] - 1;i++) { a[i][another_pos[cnt]] = cnt; } } else {// cout << cnt << "点 RIGHT" << endl; 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); } } } } //step等由这个点向外扩展的时候再更新 }
return 0;}