• UVa LA 3029 City Game 状态拆分,最大子矩阵O(n2) 难度:2


    题目

    https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1030


    题意

    矩阵,有障碍和普通地面两种子元素,求普通地面连成的子矩阵面积最大值 * 3

    思路

    如刘书

    对于子矩阵长方形来说,其底边上必然有一点,该点向上可以延伸的距离就是子矩阵的长,枚举这一点,设为(i,j)。(i,j)不是障碍是普通地面。

    令up[i][j]为其向上能延伸的距离,llen[i][j]为以up[i][j]为长的长方形,左边最早开始于哪里,rlen[i][j]为依此右边最晚结束于哪里。

    up[i][j]=(i?up[i - 1][j] + 1)

    但要如何更新llen和rlen呢?

    考虑上方(i - 1, j),如果(i - 1, j)是障碍,那么up[i][j] = 1, llen[i][j]就是(i, j)左边的障碍横坐标+1,rlen以此类推。

    如果(i- 1, j)不是障碍,第一种情况,llen[i][j] = llen[i - 1][j],在这多填出的一层内没有障碍物,另一种情况,llen[i][j]依然是(i, j)左边的障碍横坐标+1。

    rlen以此类推。

    感想

    1. 一开始没有想到枚举(i,j)这根作为面积的长,而只是想到枚举(i,j)作为右下角。这样就还要用费时间的方式确定此时的面积长。

    2. 后来没想到可以用上方而不是左方来更新rlen或者llen。没有意识到如果上方是障碍,那么只要看左/右的障碍在哪里即可。

    3. 最后本来用的是(i && maze[i - 1][j] != 'R'),不知道哪里错了

    代码

    #include <algorithm>
    #include <cassert>
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <map>
    #include <queue>
    #include <set>
    #include <tuple>
    #define LOCAL_DEBUG
    using namespace std;
    const int MAXN = 1e3 + 4;
    char maze[MAXN][MAXN];
    int up[MAXN][MAXN];
    int llen[MAXN][MAXN];
    int rlen[MAXN][MAXN];
    
    int main() {
    #ifdef LOCAL_DEBUG
        freopen("C:\Users\Iris\source\repos\ACM\ACM\input.txt", "r", stdin);
        //freopen("C:\Users\Iris\source\repos\ACM\ACM\output.txt", "w", stdout);
    #endif // LOCAL_DEBUG
        int T;
        scanf("%d", &T);
        for (int ti = 1; ti <= T; ti++) {
            int n, m;
            scanf("%d%d", &n, &m);
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    char tmp[2];
                    scanf("%s", tmp);
                    maze[i][j] = tmp[0];
                }
            }
    
            for (int i = 0; i < n; i++) {
                for (int j = 0, last_impede=-1; j < m; j++) {
                    if (maze[i][j] == 'R') {
                        up[i][j] = 0;
                        llen[i][j] = 0;
                        last_impede = j;
                    }
                    else {
                        up[i][j] = (i ? up[i - 1][j] : 0) + 1;
                        llen[i][j] = max((i ? llen[i - 1][j] : 0), last_impede + 1);
                    }
                }
            }
            int ans = 0;
            for (int i = 0; i < n; i++) {
                for (int j = m - 1, last_impede = m; j >= 0; j--) {
                    if (maze[i][j] == 'R') {
                        rlen[i][j] = m;
                        last_impede = j;
                    }
                    else {
                        rlen[i][j] = min((i ? rlen[i - 1][j] : m), last_impede - 1);
                        ans = max(ans, up[i][j] * (rlen[i][j] - llen[i][j] + 1));
                    }
                }
            }
            printf("%d
    ", ans * 3);
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    C语言编程练习51:今年暑假不AC
    C语言编程练习50:素数环
    C语言编程练习49:N皇后问题
    C语言编程练习48:士兵队列训练问题
    C语言编程练习47:看病要排队
    C语言编程练习46:度度熊学队列
    C语言编程练习44:产生冠军
    文言句式
    计算机网络
    计算机组成原理
  • 原文地址:https://www.cnblogs.com/xuesu/p/10396209.html
Copyright © 2020-2023  润新知