最大子矩形
阿新 • • 發佈:2018-08-14
cpp 排好序 aid line 所有 clu 可能 stdio.h 時間
,右移道理相通
3. 特殊情況:\(i,j\)上方的點是障礙時\(l[i][j]=\)當前行左邊最近障礙坐標\(+1\)
最後\(ans=max(ans,h[i][j]*(r[i][j]-l[i][j]+1))\)
極大子矩陣
一個\(n*m\)的矩陣中有\(s\)個位置是障礙,問最大的不包含障礙的矩形面積
最大子矩形問題-王知坤 (對於這篇論文.....吐槽無力
雖然實現..至少它的思路很對嘛
枚舉所有的極大子矩形找出最大子矩形(s^2)
悲慘經歷:找到一份題解,學學學學學學學。WA了。改改改改改改改...WA了(此處循環1w次,然後氣憤的測題解,WA了........
每個極大子矩形的每一條邊外側一定有至少一個障礙或與邊界重合,不然將邊向外移即可獲得更大子矩形,不滿足極大。因此只需要按\(y\)排好序後依次枚舉每個障礙作為左端點,然後向右找每一個點作為右端點,向上向下找出此時的上邊界和下邊界即找到了一個極大子矩形。
考慮實現找上下邊界的方法
1.先把邊界設為上下界,找到第一個點設為右邊界
2.比較這個點,若在原點和上界間的話將其設為上界,在原點和下界間的話設為下界,與原點同行的話break即可
3.再看下一個點,反復即可
#include<iostream> #include<stdio.h> #include<cmath> #include<algorithm> using namespace std; int i,m,n,j,k,ans,b[5001][5001]; char c; struct vv { int x,y; } a[1000001]; bool cmp1(vv a,vv b) {return a.x<b.x;} bool cmp2(vv a,vv b) {return a.y<b.y;} bool cmp3(vv a,vv b) {return a.y>b.y;} void dfs() { for(int i=1;i<k;i++) { int maxx=n, minn=1; for(int j=i+1;j<=k;j++) { if(a[j].y==a[i].y) continue; ans=max(ans,(abs(a[j].y-a[i].y)-1)*(maxx-minn+1)); if((a[j].x<=a[i].x)&&(a[j].x+1>minn)) minn=a[j].x+1; if((a[j].x>=a[i].x)&&(a[j].x-1<maxx)) maxx=a[j].x-1; if(-minn+maxx+1<=0) break; } } } int main() { scanf("%d%d%d",&n,&m); for(i=1;i<=n;i++) for(j=1;j<=m;j++) { scanf("%d",&j); if(j) a[++k].x=i,a[k].y=j; } a[++k].x=0; a[k].y=0; a[++k].x=0; a[k].y=m+1; a[++k].x=n+1; a[k].y=0; a[++k].x=n+1; a[k].y=m+1; sort(a+1,a+1+k,cmp1); for(i=2;i<=k;i++) ans=max(ans,(a[i].x-a[i-1].x-1)*m); sort(a+1,a+1+k,cmp2); dfs(); sort(a+1,a+1+k,cmp3); dfs(); printf("%d",ans); }
由於有時障礙可能非常密集,這個方法就會被卡掉
懸線\(O(nm)\)
由於極大子矩陣的上邊界上方一定有一個障礙,所以找出每一個點上方的最近障礙點即構成一條懸線
然後把這條懸線左右移動直到遇到障礙及構成了一個極大子矩形。
枚舉每一個點,只要能夠\(O(1)\)的間找到其為下端對應懸線和向左右能夠移動距離即可在\(O(nm)\)的時間中找到答案。
考慮預處理方法
1. 懸線長度\(h[i][j]\) 如果\(i,j\)上方的點是障礙, \(h[i][j]=1\),否則\(h[i][j]=h[i-1][j]\)
2. 左右移動距離,向左移動最大距離\(l[i][j]=max(\)當前行左邊最近障礙坐標\(+1,l[i-1][j])\)
3. 特殊情況:\(i,j\)上方的點是障礙時\(l[i][j]=\)當前行左邊最近障礙坐標\(+1\)
最後\(ans=max(ans,h[i][j]*(r[i][j]-l[i][j]+1))\)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int i,m,n,j,k,a[5001][5001],b[5001][5001],l[5001][5001],r[5001][5001],g,h,ans,las;
char c;
int main()
{
scanf("%d%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",a[i][j]);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(!a[i][j]) b[i][j]=b[i-1][j]+1;
if(a[i-1][j]) b[i][j]=1;
for(i=1;i<=n;i++)
{
las=1;
for(j=1;j<=m;j++)
{
if(a[i-1][j]) l[i][j]=las;
else l[i][j]=max(l[i-1][j],las);
if(a[i][j]) las=j+1;
}
}
for(i=1;i<=m;i++) r[0][i]=m;
for(i=1;i<=n;i++)
{
las=m;
for(j=m;j>=1;j--)
{
if(a[i-1][j]) r[i][j]=las;
else r[i][j]=min(r[i-1][j],las);
if(a[i][j]) las=j-1;
}
}
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(!a[i][j]) ans=max(ans,3*(b[i][j])*(r[i][j]-l[i][j]+1));
printf("%d",ans);
}
最大子矩形