[NOIP 2011] Mayan游戏:搜索,模拟

来源:互联网 发布:web服务器 并发 java 编辑:程序博客网 时间:2024/06/07 02:32

题意:寻找一个用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;}
0 0
原创粉丝点击