H - Maximal submatrix HDU - 6957
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了H - Maximal submatrix HDU - 6957相关的知识,希望对你有一定的参考价值。
H - Maximal submatrix HDU - 6957
题意:
给定一个n行m列的矩阵,求每列上面积不减的最大子矩阵
对于每个测试用例,打印一个表示最大子矩阵的整数
题解:
要求求一个最大面积的满足每列非递减的矩阵,这怎么想?
我们可以转化成01矩阵,每一个位置1表示该位置比上面一位大,然后求最大的01矩阵就可以了,单调栈做法时注意0的话可以作为矩阵的开始,详细看看代码
代码:
单调栈做法
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\\n",a,b);
typedef long long ll;
using namespace std;
//Fe~Jozky
const ll INF=0x3f3f3f3f;
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
return s*w;
}
int n,m;
const int maxn=2e3+9;
int a[maxn][maxn];
int h[maxn][maxn];
int w[maxn][maxn];
int st[maxn],top;
int ans=0;
void precal(){
memset(w,0,sizeof(w));
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(h[i][j]==0)w[i][j]=1;
else w[i][j]=w[i-1][j]+1;
}
w[i][m+1]=-1;
}
}
void cal(){
for(int i=1;i<=n;i++){
top==0;
for(int j=1;j<=m+1;j++){
if(top==0||w[i][j]>=w[i][st[top]]){
st[++top]=j;
}
else
{
int id;
while(top!=0&&w[i][j]<w[i][st[top]]){
id=st[top];
top--;
ans=max(ans,(j-id)*w[i][id]);
}
st[++top]=id;
w[i][id]=w[i][j];
}
}
}
}
void solve(){
n=read();m=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]=read();
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]>=a[i-1][j])h[i][j]=1;
else h[i][j]=0;
}
}
precal();
cal();
cout<<ans<<endl;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("1.in","r",stdin);
#endif
int t;
t=read();
while(t--){
ans=0;
solve();
}
fclose(stdin);
return 0;
}
纵向的悬线法
#include <iostream>
#include <cstring>
#define FAST ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define endl '\\n'
#define debug(x) cout << #x << " = " << (x) << endl
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define rep(i,a,n) for(int i=a;i<=n;++i)
#define per(i,n,a) for(int i=n;i>=a;--i)
using namespace std;
const int maxn = 2e3+5;
int n, m;
short a[maxn][maxn];
bool b[maxn][maxn];
short up[maxn][maxn], down[maxn][maxn], len[maxn][maxn];
void tran() {
mem(b, 0);
rep(i, 1, n) {
rep(j, 1, m) {
if (i == 1) continue;
else if (a[i][j] >= a[i-1][j]) b[i][j] = 1;
}
}
}
void init() {
rep(i, 1, n) {
rep(j, 1, m) {
up[i][j] = i;
down[i][j] = i;
len[i][j] = 1;
}
}
}
int main()
{
FAST;
int t; cin >> t;
while (t--) {
cin >> n >> m;
rep(i, 1, n) {
rep(j, 1, m) {
cin >> a[i][j];
}
}
tran();
init();
rep(j, 1, m) {
rep(i, 2, n) {
if (b[i][j]) up[i][j] = up[i-1][j];
}
per(i, n-1, 1) {
if (b[i+1][j]) down[i][j] = down[i+1][j];
}
}
int ans = m;
rep(j, 1, m) {
rep(i, 1, n) {
if (b[i][j-1]) {
len[i][j] = len[i][j-1] + 1;
up[i][j] = max(up[i][j], up[i][j-1]);
down[i][j] = min(down[i][j], down[i][j-1]);
}
int llen = down[i][j] - up[i][j] + 1;
ans = max(ans, llen * len[i][j]);
}
}
cout << ans << endl;
}
return 0;
}
另一种悬线法
写法就是:对于每一行的最大范围就是两侧0之间,我们设高度一开始为0,是因为每一个矩阵第一行是可以有0的,但是之后不可以,所以我们最后得到的高度还要算上第一行。相当于我们刨去第一行考虑01矩阵,最后再算上第一行
比如:01矩阵:
01011
01110
11111
我们先不考虑第一行,然后考虑后两行的左右宽度和高,左=2,右为4,高为2,那么答案就是(4-2+1)*(2+1)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=2e3+10;
int t,n,m;
int l[maxn][maxn];
int le[maxn][maxn];
int r[maxn][maxn];
int h[maxn][maxn];
int main()
{
cin>>t;
while(t--)
{
cin>>n>>m;
memset(le,0,sizeof(le));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
le[0][j]=0;
scanf("%d",&l[i][j]);
if(i!=1)
if(l[i][j]>=l[i-1][j])
{
le[i][j]=1;
}
//else le[i][j]=1;
}
}
memset(l,0,sizeof(l));
memset(h,0,sizeof(h));
memset(r,0,sizeof(r));
int ans=m;
int L=1e9,R=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(le[i][j]==1)
{
L=min (L,j);
}
else L=1e9;
l[i][j]=L;//如果当前点为0,左端点取正无穷
}
for(int j=m;j>=1;j--)
{
if(le[i][j]==1)
{
R=max(R,j);
}
else R=0;
r[i][j]=R;//如果当前端点为0,右端点取无穷小
}
for(int j=1;j<=m;j++)
{
if(le[i-1][j]==1)
{
h[i][j]=h[i-1][j]+1;
l[i][j]=max(l[i-1][j],l[i][j]);
r[i][j]=min(r[i-1][j],r[i][j]);
}
else h[i][j]=1;
if(le[i][j]==1)
{
ans=max(ans,(r[i][j]-l[i][j]+1)*(h[i][j]+1));
}
}
}
cout<<ans<<endl;
}
return 0;
}
以上是关于H - Maximal submatrix HDU - 6957的主要内容,如果未能解决你的问题,请参考以下文章
HDOJ6957Maximal submatrix(单调栈,最大子矩阵面积)