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;

}

你可能感兴趣的:(cast)