HDU 4328 Cut the cake 最大相同子矩阵, 悬线法

来源:互联网 发布:手机淘宝开店要不要钱 编辑:程序博客网 时间:2024/06/06 00:57

题目大意:

就是现在有一个n*m的矩阵(n , m <= 1000) 矩阵中每个位置要么是'R', 要么是’B', 求在所有子矩阵中, 颜色全部一样或者颜色交叉出现的子矩阵的周长最大是多少


大致思路:

白书例题的一个小变形, 还是使用悬线法来做, 用up[i][j]表示当前位置向上能匹配到的最长长度, 用left[i][j]表示保证up[i][j]的情况下向左平移的最大步数, right[i][j]表示向右平移的最大步数

于是就是一个简单的DP了, 对于颜色交叉的问题, 选择一种对角例如(i + j)是奇数的所有(i, j)位置的颜色都翻转, 那么就和上面的找相同颜色矩阵一样了

时间复杂度O(n*m)


代码如下:

Result  :  Accepted     Memory  :  8012 KB     Time  :  124 ms

/* * Author: Gatevin * Created Time:  2015/8/3 21:13:21 * File Name: Sakura_Chiyo.cpp */#include<iostream>#include<sstream>#include<fstream>#include<vector>#include<list>#include<deque>#include<queue>#include<stack>#include<map>#include<set>#include<bitset>#include<algorithm>#include<cstdio>#include<cstdlib>#include<cstring>#include<cctype>#include<cmath>#include<ctime>#include<iomanip>using namespace std;const double eps(1e-8);typedef long long lint;#define left LLLLL#define right RRRRRR#define up UUUUUUUint n, m;char maz[1010][1010];int up[1010][1010];int left[1010][1010], right[1010][1010];int solve(char color){    int ans = 0;    int le = -1, re = m;    for(int j = 0; j < m; j++)    {        if(maz[0][j] == color) up[0][j] = 1, left[0][j] = j - le;        else up[0][j] = 0, left[0][j] = 0, le = j;    }    for(int j = m - 1; j >= 0; j--)    {        if(maz[0][j] != color) re = j, right[0][j] = 0;        else right[0][j] = re - j;        int W1 = left[0][j];        int W2 = right[0][j];        if(W1 > 0 && W2 > 0)        {            int W = W1 + W2 - 1;            int H = up[0][j];            ans = max(ans, (W + H) << 1);        }    }        for(int i = 1; i < n; i++)    {        le = -1, re = m;        for(int j = 0; j < m; j++)        {            if(maz[i][j] == color)            {                up[i][j] = up[i - 1][j] + 1;                if(maz[i - 1][j] == color)                    left[i][j] = min(left[i - 1][j], j - le);                else left[i][j] = j - le;            }            else up[i][j] = 0, le = j, left[i][j] = 0;        }        for(int j = m - 1; j >= 0; j--)        {            if(maz[i][j] != color) re = j, right[i][j] = 0;            else            {                if(maz[i - 1][j] == color)                    right[i][j] = min(re - j, right[i - 1][j]);                else right[i][j] = re - j;            }            int W1 = left[i][j];            int W2 = right[i][j];            if(W1 > 0 && W2 > 0)            {                int W = W1 + W2 - 1;                int H = up[i][j];                ans = max(ans, (W + H) << 1);            }        }    }    return ans;}int main(){    int T;    scanf("%d", &T);    for(int cas = 1; cas <= T; cas++)    {        scanf("%d %d", &n, &m);        for(int i = 0; i < n; i++)            scanf("%s", maz[i]);        int ans = 0;        ans = max(solve('R'), solve('B'));        for(int i = 0; i < n; i++)            for(int j = 0; j < m; j++)                if((i + j) & 1) maz[i][j] = maz[i][j] == 'R' ? 'B' : 'R';        ans = max(ans, max(solve('R'), solve('B')));        printf("Case #%d: %d\n", cas, ans);    }    return 0;}


0 0