题目地址:http://ac.jobdu.com/problem.php?pid=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 1 1 0 0 0 0 0
- 样例输出:
0 4
解决方法:
1. 动态规划——三个状态数组,分别保存当前点的高度up,左边界left,右边界right,max_value=max(max_value,up*(right-left+1);
#include <iostream>
using namespace std;
#include <algorithm>
#define N 1000
bool data[N][N];
int up[N][N];
int l_flag[N][N];
int r_flag[N][N];
int main()
{
int m,n;
int max_1;
int l_num,r_num;
while(cin>>m>>n)
{
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
cin>>data[i][j];
max_1=0;
for(int i=0;i<m;i++)
{
l_num=-1;
r_num=n;
for(int j=0;j<n;j++)
{
if(!data[i][j])
{
up[i][j]=0;
l_flag[i][j]=0;
l_num=j;
}
else
{
if(i==0)
{
up[i][j]=1;
l_flag[i][j]=l_num+1;
}
else
{
up[i][j]=up[i-1][j]+1;
l_flag[i][j]=max(l_num+1,l_flag[i-1][j]);
}
}
}
for(int j=n-1;j>=0;j--)
{
if(!data[i][j])
{
r_flag[i][j]=n;
r_num=j;
}
else
{
if(i==0)
r_flag[i][j]=r_num-1;
else
r_flag[i][j]=min(r_num-1,r_flag[i-1][j]);
}
max_1=max(max_1,up[i][j]*(r_flag[i][j]-l_flag[i][j]+1));
}
}
cout<<max_1<<endl;
}
return 0;
}
2.向右得到每个点左边连续1的个数,如 0 1 0 1 1 0 -> 0 1 0 1 2 0。然后算每列的最大1矩阵,例如:
某列 为 1 2 3 3 4 2 0 ,得到最大1矩阵为2*5=10,具体方法为对每个元素分别向上(左)向下(右)查询连续大于等于自己的元素个数,然后相乘
此方法在九都测试超时,但是结果是对的。
#include <iostream>
using namespace std;
#include <algorithm>
bool data[1000][1000];
int flag[1000][1000];
int main()
{
int m,n;
int max_1,value,depth;
int x;
while(cin>>m>>n)
{
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
{
cin>>data[i][j];
if(data[i][j])
{
if(j==0)
flag[i][j]=1;
else
flag[i][j]=flag[i][j-1]+1;
}
else
flag[i][j]=0;
}
max_1=0;
for(int j=0;j<n;j++)
{
for(int i=0;i<m;i++)
{
if(flag[i][j]==0)
continue;
depth=1;
value=flag[i][j];
x=i;
while(x>0)
{
if(flag[--x][j]>=value)
depth+=1;
else
break;
}
x=i;
while(x<m-1)
{
if(flag[++x][j]>=value)
depth+=1;
else
break;
}
max_1=max(max_1,depth*value);
}
}
cout<<max_1<<endl;
}
return 0;
}