zoukankan      html  css  js  c++  java
  • [ABC219]E

    题意就是给你一个4*4的网格,之后网格上有一些格子被染色了。问你有多少种选择方案,使得选的所有格子包括所有被染色的格子,之后你选的格子要是一个连通块。

    attention:  不能是空心的连通块(出现回这种形状)

    首先我们看之后16个格子,自然就想到2^16次暴力枚举。之后check可不可行就行了。

    所以我们需要写三个check

    1. 是否包含所有的染色格子

    2. 是否是一个连通块

    3. 是否是一个回

    为了减少码量我就写了非递归DFS。关于判断是否是一个回我们只需要判断是不是所有0的连通块都与外部接触就行。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    typedef pair<int, int> pii;
    const int inf = 0x3f3f3f3f; ///1061109567
    const int maxn = 2e6 + 10;
    
    int housePos[5][5];
    int curOpt[5][5];
    int vis[5][5];
    int dic[4][2] = {1,0, 0,1, -1,0, 0,-1};
    
    bool check1() { ///判断是否包含
        for (int i = 1; i <= 4; ++ i)
            for (int j = 1; j <= 4; ++ j)
                if (!curOpt[i][j] && housePos[i][j]) return 1;
        return 0;
    }
    
    bool check2() { ///判断是否只有一个连通块
        memset(vis, 0, sizeof vis);
        stack<pii> sta;
        for (int i = 1; i <= 4 && !sta.size(); ++ i) {
            for (int j = 1; j <= 4 && !sta.size(); ++ j) {
                if (curOpt[i][j]) sta.push({i, j});
            }
        }
        while (sta.size()) {
            pii pos = sta.top(); sta.pop();
            int x = pos.first, y = pos.second;
            if (vis[x][y]) continue;
            vis[x][y] = 1;
            for (int k = 0; k < 4; ++ k) {
                int tx = x + dic[k][0];
                int ty = y + dic[k][1];
                if (tx < 1 || ty < 1 || tx > 4 || ty > 4 || vis[tx][ty]) continue;
                if (curOpt[tx][ty] == 0) continue;
                sta.push({tx, ty});
            }
        }
        for (int i = 1; i <= 4; ++ i) {
            for (int j = 1; j <= 4; ++ j) {
                if (vis[i][j] != curOpt[i][j]) return 1;
            }
        }
        return 0;
    }
    
    bool check3() { ///判断是否有回 (0的连通块是否都触碰到边界)
        memset(vis, 0, sizeof vis);
        stack<pii> sta;
        for (int i = 1; i <= 4; ++ i) {
            for (int j = 1; j <= 4; ++ j) {
                if (!vis[i][j] && !curOpt[i][j]) {
                    sta.push({i, j});
                    int flag = 0; ///是否触碰到边界
                    while (sta.size()) {
                        pii pos = sta.top(); sta.pop();
                        int x = pos.first, y = pos.second;
                        if (vis[x][y]) continue;
                        vis[x][y] = 1;
                        for (int k = 0; k < 4; ++ k) {
                            int tx = x + dic[k][0];
                            int ty = y + dic[k][1];
                            if (tx < 1 || ty < 1 || tx > 4 || ty > 4) {
                                flag = 1;
                                continue;
                            }
                            if (vis[tx][ty] || curOpt[tx][ty] == 1) continue;
                            sta.push({tx, ty});
                        }
                    }
    
                    if (flag == 0) return 1;
                }
            }
        }
        return 0;
    }
    
    int main() {
        for (int i = 1; i <= 4; ++ i) {
            for (int j = 1; j <= 4; ++ j) {
                scanf("%d", &housePos[i][j]);
            }
        }
        int ans = 0;
        for (int i = 0; i < (1<<16); ++ i) {
            memset(curOpt, 0, sizeof curOpt);
            for (int j = 0; j < 16; ++ j) {
                int x = j / 4 + 1;
                int y = j % 4 + 1;
                curOpt[x][y] = (i >> j) & 1;
            }
            if (check1() || check2() || check3()) continue;
            ans ++;
        }
        printf("%d
    ", ans);
        return 0;
    }
  • 相关阅读:
    又到黄金季节,该跳槽吗?怎么跳?
    分布式事务 6 个技术方案
    15 个 MyBatis 技巧,赶紧收藏吧!
    你的工资被倒挂了吗
    终于知道 Java agent 怎么重写字节码了
    每天的工作,你腻了吗?
    10 分钟轻松学会 Jackson 反序列化自动适配子类
    SpringMVC异步处理的 5 种方式
    Linux Cron 定时任务
    人类简史、软件架构和中台
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/15318250.html
Copyright © 2011-2022 走看看