1. 程式人生 > >CodeVs 1159 最大全0子矩陣【懸線法】

CodeVs 1159 最大全0子矩陣【懸線法】

時間限制: 1 s

Description

在一個0,1方陣中找出其中最大的全0子矩陣,所謂最大是指O的個數最多。

Input

輸入檔案第一行為整數N,其中1<=N<=2000,為方陣的大小,緊接著N行每行均有N個0或1,相鄰兩數間嚴格用一個空格隔開。

Output

輸出檔案僅一行包含一個整數表示要求的最大的全零子矩陣中零的個數。

題目分析

H[i][j]H[i][j]表示(i,j)(i,j)向上到第一個1的距離,也即(i,j)(i,j)為底部端點的懸線長度a[i][j]==0a[i][j]==0,則H[i][j]=H[i1][j]+

1H[i][j]=H[i-1][j]+1,否則H[i][j]H[i][j]

再定義L[i][j],R[i][j]L[i][j],R[i][j]表示以(i,j)(i,j)為底端點的懸線能向左/右擴充套件的最大距離 向左/右找到第一個H[i][k]&lt;H[i][k]H[i][k]&lt;H[i][k],那麼k就是能擴充套件到的左/右端點

最後遍歷更新答案即可ans=max(H[i][j](R[i][j]+L[i][j]1))ans=max(\ H[i][j]*(R[i][j]+L[i][j]-1)\ )

#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;
ss=getchar();} while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();} return f*x; } const int maxn=3010; int n,ans; int a[maxn][maxn]; int H[maxn][maxn],L[maxn][maxn],R[maxn][maxn]; int main() { n=read(); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) a[i][j]=read(),H[i][j]=a[i][j]==0?H[i-1][j]+1:0;; for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) { int tt=j; L[i][j]=(a[i][j]==0); while(tt>1&&H[i][tt-1]>=H[i][j]) L[i][j]++,tt--; } for(int i=1;i<=n;++i) for(int j=n;j>=1;--j) { int tt=j; R[i][j]=(a[i][j]==0); while(tt<n&&H[i][tt+1]>=H[i][j]) R[i][j]++,tt++; } for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) ans=max(ans,H[i][j]*(R[i][j]+L[i][j]-1)); printf("%d",ans); return 0; }

到這裡再次發現每次H[i][j]H[i][j]只從上一行i1i-1轉移 L[i][j],R[i][j]L[i][j],R[i][j]也只從本行的H[i][j]H[i][j]轉移,完全可以滾動陣列優化空間

#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

const int maxn=3010;
int n,ans;
int a[maxn];
int H[maxn],L[maxn],R[maxn];

int main()
{
	n=read();
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=n;++j)
		a[j]=read(),H[j]=a[j]==0?H[j]+1:0;;
	
		for(int j=1;j<=n;++j)
		{
			int tt=j; L[j]=(a[j]==0);
			while(tt>1&&H[tt-1]>=H[j]) 
			L[j]++,tt--;
		}
	
		for(int j=n;j>=1;--j)
		{
			int tt=j; R[j]=(a[j]==0);
			while(tt<n&&H[tt+1]>=H[j]) 
			R[j]++,tt++;
		}
	
		for(int j=1;j<=n;++j)
		ans=max(ans,H[j]*(R[j]+L[j]-1));
	}
	printf("%d",ans);
	return 0;
}