题意:寻找一个用n步(0<n<=5)完成5*7的Mayan游戏的字典序最小的方案。
每个方块可以左移、右移,至多5步,共有少于5.6亿个可能的情形。3秒内搜一搜是可行的。
怎样消除方块呢?由于要求一次性消完所有能消的方块,而且横、竖有公共部分则全部消掉,所以不能找到就消。找到连续三个就标记,每次循环根据标记进行清除,循环到不能再消。
怎样使方块下落呢?从下往上模拟,让方块掉到不能再掉的地方,而不是只掉一格。
BZOJ上NOIP十连测里做了一道模拟,虽然游戏不同,但是对下落的模拟是类似的。
朴素的搜索(暴力)TLE两组。什么地方可以剪枝呢?最优性?可行性?似乎都不行。有没有做重复的工作呢?有。如果有相邻的两个方块,把左边的往右移和把右边的往左移是等价的,由于要求字典序最小,考虑前者即可。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int X = 5, Y = 7, N = 5, sz = X*Y*sizeof(int);
int n, M[X][Y];
struct op {
int x, y, g;
} S[N];
inline bool empty()
{
for (int i = 0; i < X; ++i)
for (int j = 0; j < Y; ++j)
if (M[i][j])
return false;
return true;
}
void fall()
{
for (int i = 0; i < X; ++i)
for (int j = 1; j < Y; ++j) {
if (!M[i][j])
continue;
for (int k = j-1; k >= 0 && !M[i][k]; --k)
swap(M[i][k], M[i][k+1]);
}
}
void clear()
{
static bool b[X][Y];
memset(b, 0, sizeof(b));
bool ok = false;
do {
fall();
ok = true;
for (int i = 1; i < X-1; ++i)
for (int j = 0; j < Y; ++j)
if (M[i][j] && M[i-1][j] == M[i][j] && M[i][j] == M[i+1][j])
b[i-1][j] = b[i][j] = b[i+1][j] = true;
for (int i = 0; i < X; ++i)
for (int j = 1; j < Y-1; ++j)
if (M[i][j] && M[i][j-1] == M[i][j] && M[i][j] == M[i][j+1])
b[i][j-1] = b[i][j] = b[i][j+1] = true;
for (int i = 0; i < X; ++i)
for (int j = 0; j < Y; ++j)
if (b[i][j]) {
ok = false;
b[i][j] = false;
M[i][j] = 0;
}
} while (!ok);
}
bool dfs(int);
inline bool move(int d, int i, int j, int g, int T[X][Y])
{
S[d] = (op){i, j, g};
swap(M[i][j], M[i+g][j]);
clear();
bool ret = dfs(d+1);
memcpy(M, T, sz);
return ret;
}
bool dfs(int d)
{
if (d == n)
return empty();
int T[X][Y];
memcpy(T, M, sz);
for (int i = 0; i < X; ++i)
for (int j = 0; j < Y; ++j) {
if (!M[i][j])
continue;
if (i < X-1 && move(d, i, j, 1, T)
|| i && !M[i-1][j] && move(d, i, j, -1, T))
return true;
}
return false;
}
int main()
{
scanf("%d", &n);
for (int i = 0; i < X; ++i)
for (int j = 0, c; scanf("%d", &c), c; ++j)
M[i][j] = c;
if (!dfs(0))
puts("-1");
else
for (int i = 0; i < n; ++i)
printf("%d %d %d\n", S[i].x, S[i].y, S[i].g);
return 0;
}