• acwing2060. 奶牛选美


    听说最近两斑点的奶牛最受欢迎,约翰立即购进了一批两斑点牛。
    不幸的是,时尚潮流往往变化很快,当前最受欢迎的牛变成了一斑点牛。
    约翰希望通过给每头奶牛涂色,使得它们身上的两个斑点能够合为一个斑点,让它们能够更加时尚。
    牛皮可用一个 N×M 的字符矩阵来表示,如下所示:

    ................
    ..XXXX....XXX...
    ...XXXX....XX...
    .XXXX......XXX..
    ........XXXXX...
    .........XXX....
    

    其中,X 表示斑点部分。
    如果两个 X 在垂直或水平方向上相邻(对角相邻不算在内),则它们属于同一个斑点,由此看出上图中恰好有两个斑点。
    约翰牛群里所有的牛都有两个斑点
    约翰希望通过使用油漆给奶牛尽可能少的区域内涂色,将两个斑点合为一个。
    在上面的例子中,他只需要给三个 .. 区域内涂色即可(新涂色区域用 ∗ 表示):

    ................
    ..XXXX....XXX...
    ...XXXX*...XX...
    .XXXX..**..XXX..
    ........XXXXX...
    .........XXX....
    

    请帮助约翰确定,为了使两个斑点合为一个,他需要涂色区域的最少数量。

    输入格式

    第一行包含两个整数 N 和 M。

    接下来 N 行,每行包含一个长度为 M 的由 X 和 . 构成的字符串,用来表示描述牛皮图案的字符矩阵。

    输出格式

    输出需要涂色区域的最少数量。

    数据范围

    1≤N,M≤50

    输入样例:

    6 16
    ................
    ..XXXX....XXX...
    ...XXXX....XX...
    .XXXX......XXX..
    ........XXXXX...
    .........XXX....
    

    输出样例:

    3
    

    方法一:遍历两个斑点的所有可能距离

    先分别用两个vector存两个斑点上的所有点,遍历点上的所有曼哈顿距离(|x1-x2|+|y1-y2|),取最小值

    写法一:

    一开始还没理清思路,写下了这个乐色写法:先BFS找到一个斑点上的其中一个点,再BFS从该点找到该斑点,再遍历矩阵找到另一个斑点,最后遍历计算曼哈顿距离

    #include <bits/stdc++.h>
    
    using namespace std;
    
    struct Node {
        int x{}, y{};
    
        Node(int x, int y) {
            this->x = x;
            this->y = y;
        }
    
        Node() = default;;
    };
    
    string matrix[51];
    bool flag[51][51];
    int n, m;
    
    int dx[4] = {-1, 1, 0, 0};
    int dy[4] = {0, 0, -1, 1};
    
    void pushAdj(queue<Node> &q, Node &node) {
        for (int i = 0; i < 4; i++) {
            int a = node.x + dx[i], b = node.y + dy[i];
            if (a >= 0 && a < m && b >= 0 && b < n && !flag[b][a]) {
                q.emplace(a, b);
                flag[b][a] = true;
            }
        }
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n; i++)
            cin >> matrix[i];
    
        // 寻找其中一个斑点
        Node node;
        memset(flag, 0, sizeof(flag));
        flag[0][0] = true;
        queue<Node> q;
        q.push(Node(0, 0));
        while (!q.empty()) {
            node = q.front();
            q.pop();
            if (matrix[node.y][node.x] == 'X') break;
            pushAdj(q, node);
        }
        while (!q.empty()) q.pop();
    
        // 获取两个斑点
        vector<Node> dot1, dot2;
        memset(flag, 0, sizeof(flag));
        q.push(node);
        while (!q.empty()) {
            node = q.front();
            q.pop();
            if (matrix[node.y][node.x] == 'X') {
                matrix[node.y][node.x] = 'a';
                dot1.emplace_back(node.x, node.y);
                pushAdj(q, node);
            }
        }
    
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++)
                if (matrix[i][j] == 'X') dot2.emplace_back(j, i);
        }
    
        // 计算最短距离
        int res = INT_MAX;
        for (const auto &d1 : dot1) {
            for (const auto &d2 : dot2)
                res = min(res, abs(d1.x - d2.x) + abs(d1.y - d2.y));
        }
    
        printf("%d", res-1);
    
        return 0;
    }
    

    写法二:

    为了省去BFS带来的麻烦,使用DFS,在visit结点时,如果是'X'就入队。最终得到两个连通分量points[0]和[1],遍历计算曼哈顿距离

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef pair<int, int> pii;
    string matrix[51];
    int n, m;
    vector<pii> points[2];
    
    int dx[4] = {-1, 1, 0, 0};
    int dy[4] = {0, 0, -1, 1};
    
    void dfs(int x, int y, vector<pii> &point) {
        point.emplace_back(x, y);
        for (int i = 0; i < 4; i++) {
            int a = x + dx[i], b = y + dy[i];
            if (a >= 0 && a < n && b >= 0 && b < m && matrix[a][b] == 'X') {
                matrix[a][b] = '.';
                dfs(a, b, point);
            }
        }
    }
    
    int main() {
        cin >> n >> m;
        for (int i = 0; i < n; i++)
            cin >> matrix[i];
    
        int k = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++)
                if (matrix[i][j] == 'X')
                    dfs(i, j, points[k++]);
        }
    
        int res = INT_MAX;
        for (const auto &d1 : points[0]) {
            for (const auto &d2 : points[1])
                res = min(res, abs(d1.first - d2.first) + abs(d1.second - d2.second));
        }
        cout << res - 1;
    }
    

    方法二:双端队列

    TODO

  • 相关阅读:
    DWZ集成的xhEditor编辑器浏览本地图片上传的设置
    微服务看门神-Zuul
    OAuth2.0最简向导
    打造个人IP: 开源项目网站构建框架
    提前体验让人"回归Windows怀抱"的Windows Terminal
    ToB蓝海的台阶-PaaS,SaaS技术详解
    再不了解PostgreSQL,你就晚了之PostgreSQL主从流复制部署
    Netty实现高性能IOT服务器(Groza)之精尽代码篇中
    使用keepalived做High Available(HA)
    Nginx 常用配置方式说明
  • 原文地址:https://www.cnblogs.com/nosae/p/15806870.html
Copyright © 2020-2023  润新知