zoukankan      html  css  js  c++  java
  • Codeforces Round #375 (Div. 2) D. Lakes in Berland 并查集

    http://codeforces.com/contest/723/problem/D

    这题是只能把小河填了,题目那里有写,其实如果读懂题这题是挺简单的,预处理出每一块的大小,排好序,从小到大填就行了。

    以前找这些块的个数用的是dfs。现在这次用并查集做下。

    首先要解决的是,二维坐标怎么并查集,以前的并查集都是一维的,现在是两个参数,那么就考虑离散,每对应一个点,离散到一个独特的一维数值即可。我用的公式的50 * x + y。这样得到的数值是唯一的。所以可以快乐地并查集了。

    那么遇到一个'.',我们需要它和其他合并,思路就是观察其上面和左边是否存在'.',如果存在,就合并到左边(上面),没有,那就是自己一个块了。

    有顺序的,检查完上面,合并完(现在爸爸是上面那个),还要检查左边,如果有,左边的就要合并过来。这样爸爸就只是上面那个了。

    为什么要这样做呢?因为考虑下这个

    ***.**

    *. ..**

    枚举到加粗那个的时候,如果你只向左合并,则遗漏了上面那个,向上合并,又会使得左边的被算作不同的块。GG

    所以是需要两边判断,同时合并的。注意合并的方向是固定的,需要及时选择那个是爸爸

    然后就是排序删除了,每个点的爸爸是固定的,用个标记数组标记下删除了那个爸爸,输出的时候对应一下 就好

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    const int maxn = 70 * 70;
    char str[50 + 20][50 + 20];
    int fa[maxn];
    LL size[maxn];
    int calc(int x, int y) {
        return 50 * x + y;
    }
    int find(int x) {
        if (fa[x] == x) return x;
        else return fa[x] = find(fa[x]);
    }
    void merge(int x, int y) {
        x = find(x);
        y = find(y);
        if (x != y) {
            fa[y] = x;
            size[x] += size[y];
        }
    }
    int del[maxn];
    struct node {
        LL size;
        int FA;
        bool operator < (const struct node &rhs) const {
            return size < rhs.size;
        }
        node(LL aa, int bb) : size(aa), FA(bb) {}
    };
    multiset<struct node>ss;
    bool used[maxn];
    void work() {
        int n, m, k;
        scanf("%d%d%d", &n, &m, &k);
        for (int i = 1; i <= n; ++i) {
            scanf("%s", str[i] + 1);
        }
        for (int i = 0; i <= maxn - 1; ++i) {
            size[i] = 1;
            fa[i] = i;
        }
        for (int i = 1; i <= n; ++i) {
            size[calc(i, 1)] = inf;
            size[calc(i, m)] = inf;
        }
        for (int i = 1; i <= m; ++i) {
            size[calc(1, i)] = inf;
            size[calc(n, i)] = inf;
        }
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                if (str[i][j] == '.') {
                    if (str[i - 1][j] == '.' && i - 1 >= 1) {
                        merge(calc(i - 1, j), calc(i, j));
                    }
                    if (str[i][j - 1] == '.' && j - 1 >= 1) merge(calc(i, j), calc(i, j - 1));
                }
            }
        }
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                if (str[i][j] == '*') continue;
                int FA = find(calc(i, j));
                if (used[FA]) continue;
                if (size[FA] >= inf) continue;
                ss.insert(node(size[FA], FA));
                used[FA] = 1;
            }
        }
        multiset<struct node> :: iterator it = ss.begin();
        int cut = ss.size() - k;
        int ans = 0;
        while (cut--) {
            del[it->FA] = 1;
            ans += size[it->FA];
            it++;
        }
        printf("%d
    ", ans);
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                int FA = find(calc(i, j));
                if (del[FA]) {
                    printf("*");
                } else printf("%c", str[i][j]);
            }
            printf("
    ");
        }
    }
    
    int main() {
    #ifdef local
        freopen("data.txt","r",stdin);
    #endif
        work();
        return 0;
    }
    View Code
  • 相关阅读:
    第二次会议记录(2021.7.19)
    第一次会议记录(2021.7.8)
    软件工程助教工作总结
    Linux下的常用命令
    GPIO输出——使用固件库点亮LED 宏定义遇到的问题
    STM32 GPIO BRR和BSRR寄存器
    snprintf()函数使用方法
    结构体元素偏移量宏的定义及解析
    函数指针&回调函数Callback
    解析#define NULL ((void *)0)——野指针,空指针和 void*
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/5933324.html
Copyright © 2011-2022 走看看