ZZUOJ上的一道题目,原题应该是Matrix Swapping II,两道题的区别只是少了一个无关紧要的变量输入。
题目链接:矩阵大师
矩阵大师
题目描述:
给一个01矩阵,现在你可以交换任意列,交换任意次,问:
交换后的矩阵中出现的全1矩阵,面积最大是多大
01矩阵(只有 0 ,1 的矩阵 ):
00000
11111
00000
形如上面的矩阵 就是01矩阵 ,上面这个矩阵的最大全1矩形 面积为5
输入:
第一行一个T,代表有T组测试数据
每组数据第一行两个整数 n,m (n<=2000,m<=2000),代表矩阵的大小。
接下来n行,每行一个字符串,字符串大小为m,代表着01矩阵
保证 n*m的总和不超过2000000
输出:
T行,输出最大全1矩阵面积
分析
题目的做法类似于动态规划,但不同的是划分的各个子问题间并没有‘无后效性’,答案是从所有子问题中取最大值。可以按照如下思路:
①若矩阵只有一行,如何求最大面积?由于列的顺序可以随意改变,那么将所有值为1的列连在一起,就得到了答案
②若矩阵有两行,如何求最大面积?首先,我们分析两种情况。
壹 这个最大矩阵中只有第一行的元素,而没有第二行的元素,这个情况就可以直接看作问题①了,因为只需要查看第一行的元素组成的最大矩阵,就能知道答案。
贰 这个最大矩阵同时包含了两行的元素。既然它必然包含第二行的元素,那么我们就将所有第二行为1的列先拼在一起,因为这样使得最大矩阵在第二行的可能宽度达到最大,这里使用了贪心算法的思想;之后,我们按照每一列第二行元素[与其相连的上方的1]的数量,对其降序排列,因为这样使得最大矩阵在第一行的可能宽度也达到最大。此时,设i=1,并遍历到m,代表最大矩阵中的元素跨越了第1列到第i列,即矩阵宽度为i,易知矩阵长度为[与第二行元素相连的上方的1]的数量,两者相乘即获得面积。遍历完成后,取得到的所有面积的最大值,就是答案。
③若矩阵有n行,如何求最大面积?显然,只要将②的情况推广即可。
完成题目的重点只有两个:获得每个元素与其相连的上方的1的数量;对每一行进行遍历时,根据这个数量进行排序求面积。
代码里用%d读了数据,其实直接用%s读更方便,不过一些地方需要做细小的变更
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define max(a,b) a>b?a:b
#define zo(a) a=='1'?1:0
int main()
{
int n,m,time;
static int dp[2020][2020],s[2020];
scanf("%d",&time);
while(time--)
{
scanf("%d%d",&n,&m);
int ans=0;
for(int i=1;i<=n;i++)
{
getchar();
for (int j=1;j<=m;j++)
{
dp[i][j]=zo(getchar());
if (dp[i][j]==1)
dp[i][j]=dp[i-1][j]+1;
s[j]=dp[i][j];
}
std::sort(s+1,s+m+1);
for (int j=1;j<=m;j++)
{
ans=max(ans,s[j]*(m-j+1));
}
}
printf("%d\n",ans);
}
}