線性dp之懸線法學習筆記

懸線法

以前寫過求最大正方形面積的題目,這隻要處理 [i-1][j],[i][j-1],[i-1][j-1] 三個位置的最小值就可以,用不到懸線法,簡單的線性dp;

但是當要求最大長方形時,那種方法就不適合了,懸線法就出現了;

模板題: P4147 玉蟾宮

懸線法可以分爲三個部分:

  1. l[i][j] 代表位置 (i,j) 可以往左擴展的最小座標,就是最遠的座標
  2. r[i][j] 代表位置 (i,j) 可以往右擴展的最大座標,就是最遠的座標
  3. up[i][j] 代表位置 (i,j) 可以往上擴展的最大距離,不是座標了

l,r 數組都要進行預處理,最關鍵的是在進行dp時,l 數組要取最大值,r 數組要取最小值,up 數組加 1 ,就跟求最大正方形面積的思路是一樣的,要保證最短的也符合條件;

代碼:

#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=1100;
const int M=50100;
const int mod=1e9;
int n,m,a[N][N];
int l[N][N],r[N][N],up[N][N];
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			char c;cin>>c;
			if(c=='F') a[i][j]=1;	
			up[i][j]=1,l[i][j]=r[i][j]=j;
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=2;j<=m;j++){
			if(a[i][j]&&a[i][j-1]) l[i][j]=l[i][j-1];
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=m-1;j>=1;j--){
			if(a[i][j]&&a[i][j+1]) r[i][j]=r[i][j+1]; 
		}
	}
	int ans=0;
	for(int i=2;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(a[i][j]&&a[i-1][j]){
				l[i][j]=max(l[i][j],l[i-1][j]);
				r[i][j]=min(r[i][j],r[i-1][j]);
				up[i][j]=up[i-1][j]+1;	
			}
			ans=max(ans,(r[i][j]-l[i][j]+1)*up[i][j]);
		}
	}
	cout<<ans*3<<endl; 
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章