hdu4328 最大子矩阵问题O(n*m)扫描思想

http://acm.hdu.edu.cn/showproblem.php?pid=4328

Problem Description

Mark bought a huge cake, because his friend ray_sun’s birthday is coming. Mark is worried about how to divide the cake since it’s so huge and ray_sun is so strange. Ray_sun is a nut, you can never imagine how strange he was, is, and going to be. He does not
eat rice, moves like a cat, sleeps during work and plays games when the rest of the world are sleeping……It is not a surprise when he has some special requirements for the cake. A considering guy as Mark is, he will never let ray_sun down. However, he does
have trouble fulfilling ray_sun’s wish this time; could you please give him a hand by solving the following problem for him?

The cake can be divided into n*m blocks. Each block is colored either in blue or red. Ray_sun will only eat a piece (consisting of several blocks) with special shape and color. First, the shape of the piece should be a rectangle. Second, the color of blocks
in the piece should be the same or red-and-blue crisscross. The so called ‘red-and-blue crisscross’ is demonstrated in the following picture. Could you please help Mark to find out the piece with maximum perimeter that satisfies ray_sun’s requirements?

Input

The first line contains a single integer T (T <= 20), the number of test cases.

For each case, there are two given integers, n, m, (1 <= n, m <= 1000) denoting the dimension of the cake. Following the two integers, there is a n*m matrix where character B stands for blue, R red.

Output

For each test case, output the cased number in a format stated below, followed by the maximum perimeter you can find.

Sample Input

2
1 1
B
3 3
BBR
RBB
BBB

Sample Output

Case #1: 4
Case #2: 8
/**
hdu4328 最大子矩阵问题O(n*m)
题目大意:给定一个n*m的棋盘有红黑两色,让截取一个周长最大矩形,该矩形要么全是黑色,要么全是红色,要么黑色和红色交替
           见题目附图。
解题思路:如果遍历每一个矩阵是不可能的,时间O(n*n*n),因此我们采用扫描的方法(白书P51)。对于交替的矩形我们把(i+j)
           为奇数的格子翻转颜色,那样就可以转换成全是一样颜色了,然后边成把(i+j)为偶数的翻转,四种情况取最大即可。复杂度O(n*m)
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;

const int maxn=1005;
int mat[maxn][maxn],mat1[maxn][maxn],up[maxn][maxn],lef[maxn][maxn],rig[maxn][maxn];
char a[maxn][maxn];
int n,m;
int get()
{
    int ans=0;
    for(int i=0; i<m; i++)
    {
        int lo=-1,ro=n;
        for(int j=0; j<n; j++)
        {
            if(mat[i][j]==1)
            {
                up[i][j]=lef[i][j]=0;
                lo=j;
            }
            else
            {
                up[i][j]=i==0?1:up[i-1][j]+1;
                lef[i][j]=i==0?lo+1:max(lef[i-1][j],lo+1);
            }
        }
        for(int j=n-1; j>=0; j--)
        {
            if(mat[i][j]==1)
            {
                rig[i][j]=n;
                ro=j;
            }
            else
            {
                rig[i][j]=i==0?ro-1:min(rig[i-1][j],ro-1);
                ans=max(ans,up[i][j]*2+2*(rig[i][j]-lef[i][j]+1));
            }
        }
    }
    return ans;
}
int main()
{
    int tt=0,T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&m,&n);
        for(int i=0; i<m; i++)
        {
            scanf("%s",a[i]);
        }
        for(int i=0; i<m; i++)
        {
            for(int j=0; j<n; j++)
            {
                if(a[i][j]=='R')
                    mat1[i][j]=mat[i][j]=1;
                else
                    mat1[i][j]=mat[i][j]=0;
            }
        }
        int ans=-1;
        ///1
        ans=max(ans,get());
        ///2
        for(int i=0; i<m; i++)
        {
            for(int j=0; j<n; j++)
            {
                if(mat1[i][j]==1)
                    mat[i][j]=0;
                else
                    mat[i][j]=1;
            }
        }
        ans=max(ans,get());
        ///3
        for(int i=0; i<m; i++)
        {
            for(int j=0; j<n; j++)
            {
                if((i+j)%2==1)
                {
                    if(mat1[i][j]==1)
                        mat[i][j]=0;
                    else
                        mat[i][j]=1;
                }
                else
                    mat[i][j]=mat1[i][j];
            }
        }
       /* for(int i=0; i<m; i++)
        {
            for(int j=0; j<n; j++)
            {
                printf("%d",mat[i][j]);
            }
            printf("\n");
        }
        printf("\n");*/
        ans=max(ans,get());
        ///4
        for(int i=0; i<m; i++)
        {
            for(int j=0; j<n; j++)
            {
                if((i+j)%2==0)
                {
                    if(mat1[i][j]==1)
                        mat[i][j]=0;
                    else
                        mat[i][j]=1;
                }
                else
                    mat[i][j]=mat1[i][j];
            }
        }
        /*for(int i=0; i<m; i++)
        {
            for(int j=0; j<n; j++)
            {
                printf("%d",mat[i][j]);
            }
            printf("\n");
        }
        printf("\n");*/
        ans=max(ans,get());
        printf("Case #%d: %d\n",++tt,ans);
    }
    return 0;
}
/**
100
3 3
BBR
RBR
BBB

2 2
BR
RB

2 2
BB
RR

2 2
BB
BB
*/
时间: 2024-10-18 14:49:34

hdu4328 最大子矩阵问题O(n*m)扫描思想的相关文章

SWJTU 2208 最大覆盖

最大覆盖 Time Limit:1000MS  Memory Limit:32768KTotal Submit:20 Accepted:7 Description 我们定义一条线段,首先可以认为它在X轴上,它的起点为(a,0)终点为(b,0),所以我们可以简化成[a,b].现在我们有N条这样的线段都位于X轴上,所以肯定存在一点被覆盖多次或者一次,我们的任务就是找到最多被覆盖的次数,请参考样例便于理解. Input 第一行输入为一个整数N(1≤N≤10^5),表示我们有N条线段,接下来的N行每行包

面积最大的全1子矩阵--九度OJ 1497

题目描述: 在一个M * N的矩阵中,所有的元素只有0和1,从这个矩阵中找出一个面积最大的全1子矩阵,所谓最大是指元素1的个数最多. 输入: 输入可能包含多个测试样例.对于每个测试案例,输入的第一行是两个整数m.n(1<=m.n<=1000):代表将要输入的矩阵的大小.矩阵共有m行,每行有n个整数,分别是0或1,相邻两数之间严格用一个空格隔开. 输出: 对应每个测试案例,输出矩阵中面积最大的全1子矩阵的元素个数. 样例输入: 2 2 0 0 0 0 4 4 0 0 0 0 0 1 1 0 0

最大子序列和最大子矩阵

最大子序列: 问题描述:给定整数序列:a1,a2,a3,...an(可能有负数),求a1~an的一个子序列ai~aj,使其和最大 我们很容易想到一个O(n^2)复杂度的方法,即 i : 1--->n,并令 s = 0,然后 j : i---->n, s<---s + a[j],更新maxsum,如若想得到具体的子序列,我们可设i1,j1,更新maxsum时,同时更新下标,不过为了减少运算,我们在更新时做个判断if i1 ≠ i,i1<--i int sub_sum(int *a,i

最大全0/1子矩阵的探究

by MedalPluS [问题模型] 给定一个n*n的矩阵,求矩阵中面积最大的一个值全是0或1的子矩阵 [分析] (这里n*n完全可以改为n*m,但由于种种原因,等下代码里是n*n) 首先很容易想到一种解法,枚举这个子矩阵的左上方,和右下方,然后暴力统计,这样时间复杂度O(N6),这种做法很广泛 这肯定是不能满足我们的需求,那么应该怎么办呢?我们发现O(n2)的时间浪费在统计上,我们可以使用前缀和的手段,预处理 这样时间复杂度O(n4),还是很垃圾 在暴力种种优化都不行的时候,想一想贪心或者数

洛谷 U360 子矩阵 (NOIP模拟赛T1)题解

题目链接:https://www.luogu.org/problem/show?pid=U360 题目背景 夏令营 题目描述 小A有一个N×M的矩阵,矩阵中1~N*M这(N*M)个整数均出现过一次.现在小A在这个矩阵内选择一个子矩阵,其权值等于这个子矩阵中的所有数的最小值.小A想知道,如果他选择的子矩阵的权值为i(1<=i<=N×M),那么他选择的子矩阵可能有多少种?小A希望知道所有可能的i值对应的结果,但是这些结果太多了,他算不了,因此他向你求助. 输入输出格式 输入格式: 第一行,两个整数

BZOJ 1057 棋盘制作(最大黑白相间子矩阵)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1057 题意:给出一个只包含01的矩阵.找出一个01相间的最大的正方形子矩阵?找出一个01相间的最大的长方形子矩阵? 思路:一行一行扫描,对于某一行,记录每列 向上延伸的最大长度,记为h.然后再求出每列向右向左延伸的最大距离.比如2122345421,第4个位置的2向左延伸到3向右延伸到9.我们就是要求 出这个东西.我们用类似并查集思想.以向左为例.L[j]初始时指向j.从左向右扫描,对

Vijos 1055 奶牛浴场 最大子矩阵 算♂法①

题意:链接 方法:最大子矩阵之算♂法① 解析: 首先谈到最大子矩阵,我们可能会想到之前做过的盖房子?,那道DP求解的题目. 然而这种题目当然有更高♂端的算法. 比如接下来要谈到的算法①. 我们先来观察数据范围,n,m<=30000,这下就玩完了,怎么dp? 一下子就D掉了你原来的算法,真是不留情面. 那么我们来介绍一种新的算法. 首先谈暴力,枚举各种坏点,但这种的复杂度呢?甚至可能达到6次方,所以怎么优化呢? 按照经验,这种坐标图排个序就能降下复杂度什么的. 于是有神犇介绍了s^2复杂度的算法,

AppScan代理扫描app/H5安全测试

1.首先设置AppScan代理,设置如下: 2.设置手机端代理: 3.通过外部设备调用,记录请求: 直接点击确定,即可扫描到所有的请求

微信服务器与项目服务器的交互(关注功能、微信扫描带参数二维码)

<?php /** * wechat php test */ //define your token define("TOKEN", "txtj"); $wechatObj = new wechatCallbackapiTest(); if (isset($_GET['echostr'])) { $wechatObj->valid(); }else{ $wechatObj->responseMsg(); } class wechatCallback