POJ 2044 Weather Forecast(DFS + 强剪枝)

题意:

有一朵2*2的云朵,和一个4*4的地区。被云层覆盖的区域在当天一定有雨下,云层有4种移动方式 。但是规定在城市或者节日期间希望不要下雨,而且一个地方不能有连续7天没下雨。

思路:

1. 要保证 16 方块中每个方块都在 7 天内被下过雨,因为云块是 2*2 的,所以则只需保证(0,0)(0,1)(1,0)(1,1)四个角落满足上述要求即可;

2. 对于云块,每次有 9 种不同的选择,上下左右,走1步2步,或者不动,针对这 9 种情况,深度搜索即可;

3. 暴力的搜索方法结果就是 TLE,这次采取一种记忆化剪枝的方法,vis[] 标记数组表示:第 k 天,云块处在第 x 位置时,四个角落上面各多少天没被下雨的情况,

   如果被递归树某个分支访问过了,则标记为 true。因为 16 方块,访问密集度很高,如果下次再访问,说明重复,则剪枝。这种方法能有效的降低时间;

4. 对于某一天的城市情况,则可以用位运算来表示,只需要一个 int 就能满足需求, 最终代码跑到了 110ms ;

 

#include <iostream>
#include <algorithm>
using namespace std;

struct ST {
    int c00, c01;
    int c10, c11;
    ST() : c00(0), c01(0), c10(0), c11(0) {}
};

struct POS {
    int x, y;
    POS(int _x, int _y) : x(_x), y(_y) {}
};

const int dir[9][2] = {{0,0},{-1,0},{-2,0},{0,-1},
                  {0,-2},{1,0},{2,0},{0,1},{0,2}};
bool vis[370][9][7][7][7][7];
int day[370], N;

inline int getflag(int r) {
    return 1 << r;
}

bool judge(int k, const POS& u, const ST& s) {
    if (s.c00 == 7 || s.c01 == 7 || s.c10 == 7 || s.c11 == 7) 
        return false;

    int flag = 0;
    int x = u.x, y = u.y;
    flag |= getflag(4*x + y) | getflag(4*x + y+1);
    flag |= getflag(4*(x+1) + y) | getflag(4*(x+1) + y+1);
    if (flag & day[k])
        return false;

    if (vis[k][3*x+y][s.c00][s.c01][s.c10][s.c11])
        return false;
    vis[k][3*x+y][s.c00][s.c01][s.c10][s.c11] = true;
    return true;
}

bool dfs(int k, const POS& u, const ST& state) {
    if (k == N)
        return true;

    ST s = state;
    s.c00 += 1, s.c01 += 1;
    s.c10 += 1, s.c11 += 1;

    if (u.x == 0 && u.y == 0)
        s.c00 = 0;
    else if (u.x == 0 && u.y == 2)
        s.c01 = 0;
    else if (u.x == 2 && u.y == 0)
        s.c10 = 0;
    else if (u.x == 2 && u.y == 2)
        s.c11 = 0;

    if (!judge(k, u, s))
        return false;

    for (int i = 0; i < 9; i++) {
        int x = u.x + dir[i][0];
        int y = u.y + dir[i][1];
        if (0 <= x && x < 3 && 0 <= y && y < 3) {
            if (dfs(k + 1, POS(x, y), s))
                return true;
        }
    }
    return false;
}

int main() {
    while (scanf("%d", &N) && N) {
        for (int i = 0; i < N; i++) {
            day[i] = 0;
            for (int j = 0; j < 16; j++) {
                int x;
                scanf("%d", &x);
                day[i] <<= 1;
                day[i] |= x;
            }
            memset(vis[i], false, sizeof(vis[i]));
        }
        ST s;
        if (dfs(0, POS(1, 1), s))
            printf("1\n");
        else
            printf("0\n");
    }
    return 0;
}
posted @ 2013-03-27 22:50  kedebug  阅读(728)  评论(0编辑  收藏  举报