CF-Codeforces Round #639 (Div. 2)-D-Monopole Magnets

题目传送门

sol:有三种情况无法构造满足条件的答案。

  1. 出现同一行(列)的两个'#'之间隔着一段'.'的情况,比如样例2。如果两个'#'之间隔着一段'.',那么在这一行(列)就无法放置南磁铁,因为'#'代表北磁铁可以到达,若在这一行(列)任意位置放置南磁铁,会导致这两个'#'中的至少一个北磁铁被吸到中间的'.'部分。这是违反第三条规则的。
  2. 每一列都出现过至少一个北磁铁,同时还有全是'.'的行出现,比如样例4,。样例4中只有一列,在这一列中出现了'#',同时第一行全都是'.',这将导致第一行无法放置南磁铁,因为在这一行的任意位置放置南磁铁都会将对应列'#'中的北磁铁吸到这一行的'.',这同样是违反第三条规则的。
  3. 根据第二种情况可以得出,如果每一行都出现过至少一个北磁铁,同时还有全是'.'的列出现。也是无法构造满足条件的答案的。例子就是样例4旋转90度。这会导致全是'.'的列无法放置南磁铁。

   除了上述三种情况,必能构造合法答案。如果,某一行(列)中出现了'#'那就在'#'里面放置南磁铁,可以在所有'#'里面都放置一个南磁铁。如果这一行(列)中没有出现过'#',就找一个没有出现过'#'的列(行)放置南磁铁。比如样例3中第一行第五列的'#'变成了'.'那第一行的南磁铁依然放在第五列,因为第五列将没有'#'。最终需要的北磁铁的数量就是联通块的数量。

  • 深度优先搜索
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int, int> PII;
    const int MAXN = 1010;
    char mp[MAXN][MAXN];
    inline int read() {
        int n = 0, f = 1; char c = getchar();
        while (c < '0' || c > '9') {
            if (c == '-') f = -f;
            c = getchar();
        }
        while (c >= '0' && c <= '9') {
            n = 10 * n + (c ^ '0');
            c = getchar();
        }
        return f * n;
    }
    void dfs(int i, int j) {
        mp[i][j] = '.';
        if (mp[i + 1][j] == '#') dfs(i + 1, j);
        if (mp[i][j + 1] == '#') dfs(i, j + 1);
        if (mp[i - 1][j] == '#') dfs(i - 1, j);
        if (mp[i][j - 1] == '#') dfs(i, j - 1);
    }
    int main() {
        int n = read(), m = read();
        for (int i = 1; i <= n; i++) scanf("%s", mp[i] + 1);
        int row = 0, col = 0; bool has = 1;
        // 找有多少个行出现过'#'
        for (int i = 1; i <= n; i++) {
            bool ok = 0;
            for (int j = 1; j <= m; j++) {
                if (mp[i][j] == '#') {
                    ok = 1;
                    break;
                }
            }
            row += ok;
        }
        // 找有多少个列出现过'#'
        for (int j = 1; j <= m; j++) {
            bool ok = 0;
            for (int i = 1; i <= n; i++) {
                if (mp[i][j] == '#') {
                    ok = 1;
                    break;
                }
            }
            col += ok;
        }
        for (int i = 1; i <= n; i++) {
            int l = -1, r = -1;
            for (int j = 1; j <= m; j++) {
                if (mp[i][j] == '#') {
                    if (l != -1) r = j;
                    else l = r = j;
                }
            }
            // 这一行没有'#'同时每一行都出现过'#',则无法构造合法解
            if (l == -1) {
                if (col == m) has = 0;
                continue;
            }
            // 找是否有某行两个'#'之间出现'.'
            for (int j = l; j <= r; j++) {
                if (mp[i][j] != '#') {
                    has = 0;
                    break;
                }
            }
        }
        for (int j = 1; j <= m; j++) {
            int l = -1, r = -1;
            for (int i = 1; i <= n; i++) {
                if (mp[i][j] == '#') {
                    if (l != -1) r = i;
                    else l = r = i;
                }
            }
            // 这一列没有'#'同时每一行都出现过'#',则无法构造合法解
            if (l == -1) {
                if (row == n) has = 0;
                continue;
            }
            // 找是否有某列两个'#'之间出现'.'
            for (int i = l; i <= r; i++) {
                if (mp[i][j] != '#') {
                    has = 0;
                    break;
                }
            }
        }
        if (has == 0) return 0 * puts("-1");
        int ans = 0;
        // dfs找联通块
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (mp[i][j] == '#') dfs(i, j), ans ++;
            }
        }
        printf("%d\n", ans);
        return 0;
    }

    ------------------------------------------------------------分隔线------------------------------------------------------------

    总结:这种题型好像做的不多,这题也算印象深刻了,考虑到了第二种无解情况居然忽略了第三种无解情况。评测机还挂了不给评测结果。这场居然urt了,不然应该就上紫了,想上个紫好难啊!!!

posted @ 2020-05-07 14:07  Jathon-cnblogs  阅读(238)  评论(0编辑  收藏  举报