• 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;
    }
  • 相关阅读:
    怎样从youtube或国内视频网站上下载视频(FLV Downloader) 转
    C#实现图片文件到数据流再到图片文件的转换 转
    C#中事件与事件订阅搞不懂 转
    水晶报表的使用 转
    DataGridView列头设置 转
    详解C#委托,事件与回调函数 转载
    新开通blog,开庆祝
    C#下实现空白窗体上中文输入,可以实现类PS的文字工具
    java 内存爆满排查命令
    ECMAScript 面向对象技术:创建你自己的对象
  • 原文地址:https://www.cnblogs.com/kedebug/p/2985693.html
Copyright © 2020-2023  润新知