# Dynamic Programming# Greedy# Array

e560 - 10074 - Take the Land

🔗 前往 ZeroJudge 原題

題目描述

題目要求找出一個二維地圖中,由 0 表示的、面積最大的矩形區域。地圖由 1 和 0 組成,1 表示有樹木,0 表示空地。

解題思路

程式碼使用動態規劃 (Dynamic Programming) 的方法來解決這個問題。首先,對於地圖中的每一行,計算從該行中的每一列開始,連續有多少個 0。這個資訊儲存在 dp 陣列中。然後,對於地圖中的每一列,檢查以該列為右邊界的矩形的最大高度。最後,計算以每一列為右邊界的最大矩形面積,並更新最大面積。

具體來說,dp[i][j] 儲存的是地圖第 i 行,從第 j 列開始,連續有多少個 0。然後,對於每一列 j,程式碼遍歷每一行 i,如果 a[i][j] 為 0,則 dp[i][j] 的值等於 dp[i][j-1] + 1。如果 a[i][j] 為 1,則 dp[i][j] 為 0。

計算最大矩形面積時,程式碼遍歷每一列 j,對於每一列,計算以該列為右邊界的最大矩形面積。對於每一行 i,如果 a[i][j] 為 0,則計算以該行和該列為右下角的矩形面積。矩形的寬度由 dp[i][j] 決定,高度由從第 i 行向上連續有多少個 0 決定。

複雜度分析

  • 時間複雜度: O(n^3)
  • 空間複雜度: O(n^2)

程式碼

#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#define max( x, y )  ( ((x)>(y)) ? (x):(y) )
#include <stdio.h>
int n,m,dp[101][101],ans;
char a[101][101];
inline int read(){
	int a(0);
	char c('0');
	while(c>='0'){
		a=(a<<3)+(a<<1)+c-'0';
		c=getchar_unlocked();
	}
	return a;
}
inline void write(int x) {
	int stk[9],*ptr(&stk[0]);
	while(x){*ptr=x%10;x/=10;++ptr;}
	while(--ptr>=(&stk[0])){putchar_unlocked(*ptr+'0');}
}
int main(){
	while(n=read()){
		m=read();
		if(n==0&&m==0)break; 
		for(int i=0;i<101;++i)
			for(int j=0;j<101;++j){
				dp[i][j]=0;
				a[i][j]=0;
			}
		ans=0;
		for(int i=0;i<n;++i)
			for(int j=0;j<m;++j){
				a[i][j]=read();
				a[i][j]=!a[i][j];
			}
		for(int i=0;i<n;++i)
			for(int j=0;j<m;++j)
				if(a[i][j])
					for(int jj=j;jj>=0;--jj){
						if(a[i][jj])
							++dp[i][j];
						else
							break;
					}
		for(int i=0;i<n;++i)
			for(int j=0;j<m;++j)
				if(a[i][j])
					if(dp[i][j]*(n-i)>ans)
						for(int k=1;k<=dp[i][j];++k){
							int tmp=0;
							for(int ii=i;ii<=n;++ii){
								if(dp[ii][j]>=k)
									tmp+=k;
								else{
									ans=max(tmp,ans);
									break;
								}
							}
						}
		write(ans);
		putchar_unlocked('\n');
	}
}

Discussion