“Shopee杯” 武汉大学(网络预选赛)D - DIY Masks at Home

“Shopee杯” 武汉大学(网络预选赛)D - DIY Masks at Home

题目链接:Click

时间限制:C/C++ 5秒,其他语言10秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

During the outbreak of COVID-19, xyjj has to stay at home for a long time, which is because he doesn’t have any mask. If he wants to go outside, he must wear a mask to avoid being infected. But if he wants to have a mask, he must go outside to buy one!

Finally, he came up with a solution: Why not DIY at home! Quickly he found the materials required: scissors, needle and threads, and a large piece of cloth (cut from the curtains of his room). To make a mask, he need to cut out a piece of square cloth, and other part of the mask can be easily made so it doesn’t matter. The original cloth can be regarded as a rectangle of n * m cm2, which is made up of 1×1 small colorful squares as the image showing below.

(That’s a typical programmer’s style, isn’t it?)
“Shopee杯” 武汉大学(网络预选赛)D - DIY Masks at Home_第1张图片
However, xyjj doesn’t want his mask to be colorful, so he want the square he selected to have only one single color. Meanwhile, he wants the square to be cut out as large as possible, or the mask might not be able to cover his face. Can you help him with this problem?

输入描述

The input consists of several test cases. The first line contains an integer T, the number of test cases.
For each test case:
The first line will be two integers n, m, which describe the size of the cloth.
For the next n lines, each line will be a string of m upper-case Latin letters, which describe the pattern of the cloth. Each letter refers to a kind of color and places which have the same letters also have the same color
Here it’s guaranteed that .1 ≤ n, m ≤ 2000 and ∑n, ∑m ≤ 2000 for all test cases.

输出描述

For each test case, print one integer ansans in a single line, which is the maximum length of the square we can get. (i.e the result square’s size will be ans*ans cm2).

样例输入#1

1
3 4
AABB
AACC
CCCC

样例输出#1

2

题意

从输入矩阵中,找到最大方形矩阵(同色),输出边长。

分析

别看 n 只有2000,如果暴力的话会变成 2000*2000*2000*2000*k
所以,其实大部分关于最大子矩阵问题,都是dp啦

这题思路还是比较清晰的,关键在于如何寻找状态转移方程,(好吧,dp都这样)

如此定义:dp[i][j] 表示以第 i 行 第 j 列元素为右下角的 子矩阵最大边长
(当然实际上我是从0 0 开始计数的)
状态转移方程:
①若map[i][j] != map[i-1][j-1]
dp[i][j]=1,此时只有一个元素

②若map[i][j] == map[i-1][j-1]
此时计算向上和向左能拓展的最大长度 t
if (t>dp[i-1][j-1]) dp[i][j] = dp[i-1][j-1]+1 拓展一格
否则
dp[i][j]=t; 自立门户
如:
AAAB
AAAB
AAAA
BBAA
对于最后一个元素,t=2,不能拓展,只能自立门户

"Talk is Cheap. Show me the Code."

#include
#include
#include
#include
using namespace std;
const int maxn = 2005;
typedef long long ll;
char map[maxn][maxn];
int dp[maxn][maxn];
int main(void)
{
    int T;
    scanf("%d", &T);
    while (T--) {
        int n, m;
        scanf("%d %d", &n, &m);
        memset(dp, 0, sizeof(dp));
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                scanf(" %c", &map[i][j]);
        for (int i = 0; i < n; i++)//初值
            dp[i][0] = 1;
        for (int j = 0; j < m; j++)
            dp[0][j] = 1;
        int ans = 1;
        for(int i=1;i<n;i++)
            for (int j = 1; j < m; j++) {
                if (map[i][j] != map[i - 1][j - 1]) {
                    dp[i][j] = 1;
                    continue;
                }
                int l = j, u = i, t = 0;
                while (l >= 0 && u >= 0 && map[i][l] == map[i][j] && map[u][j] == map[i][j])
                    l--, u--, t++;//向上,向左拓展
                if (t > dp[i - 1][j - 1])
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                else
                    dp[i][j] = t;
                ans = max(ans, dp[i][j]);
            }
        printf("%d\n", ans);
    }
    return 0;
}

突然发现这题给了5s,很给面子
感谢 sjjda 指出错误

你可能感兴趣的:(ACM)