“Shopee杯” 武漢大學(網絡預選賽)D - DIY Masks at Home
時間限制: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?)
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<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
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 指出錯誤