之前的考試包括做題都有用過這個方法,算是個套路了。寫一篇部落格總結一下。
懸線法的用途
針對求給定矩陣中滿足某條件的極大矩陣,比如「面積最大的長方形、正方形」「周長最長的矩形等等」。可以滿足在時間複雜度為o(m*n)的要求,比一般的列舉高效的多,也易於理解。
懸線法的思路
懸線法,懸線的定義,就是一條豎線,這條豎線要滿足上端點在整個矩形上邊界或者是乙個障礙點。然後以這條懸線進行左右移動,直到移至障礙點或者是矩陣邊界,進而確定這條懸線所在的極大矩陣。也就是說,我們要針對矩陣中每個點進行求極大矩陣的操作。所以我們要$left$陣列來存每個點能到達的最左的地方,$right$陣列存每個點能到達的最右的地方。同時設定乙個$up$陣列表示最上能到達的地方,用來存矩形的上邊界。有轉移:
$r[i][j]=r[i][j+1](a[i][j]==a[i][j+1])$
$l[i][j]=l[i][j-1](a[i][j]==a[i][j-1])$
$up[i][j]=up[i-1][j]+1(a[i][j]==a[i-1][j])$
同時,在$up$進行轉移的同時$left$和$right$要進行更新。
例題
1.棋盤製作
裸題了。直接上套路即可。
**:
#include#includeusing
namespace
std;
const
int n=2005
;int
l[n][n],r[n][n],up[n][n],a[n][n],n,m,ans1,ans2;
inline
intread()
while(isdigit(ch))
return x*f;
}int
main()
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
];
for (int i=2;i<=n;i++)
for (int j=1;j<=m;j++)
int a=r[i][j]-l[i][j]+1
;
int b=min(a,up[i][j]);
ans1=max(ans1,b*b);
ans2=max(ans2,a*up[i][j]);
}printf(
"%d\n%d
",ans1,ans2);
return0;
}
2.奶牛浴場
這題在洛谷的資料加強後好多題解都被hack掉了。連wzk大佬**裡面的**也有bug233。
大體的思想是按照橫座標排序後選取兩個點作為矩形的兩個角計算面積,同時更新上下邊界。從左到右掃完後從右到左再掃一遍。最後還有按照縱座標排序再掃一遍。證明可以看洛谷第二篇題解。
**:
#include#include#include
using
namespace
std;
const
int n=5050
;int
l,w,n,ans;
struct
node
a[n];
inline
intread()
while(isdigit(ch))
return x*f;
}bool
cmp1(node x,node y)
bool
cmp2(node x,node y)
intmain()
}for (int i=n;i>=1;i--)
}sort(a+1,a+n+1
,cmp2);
for (int i=1;i)
ans=max(ans,l*(a[i+1].y-a[i].y));
printf("%d
",ans);
return0;
}
懸線法 學習總結
主要用於求滿足某條件的最大矩陣 一條豎線,豎線的上端點位於矩陣的上邊界或是乙個障礙點,然後對這條懸線進行左右移動,直到移至障礙點或者是矩陣邊界,進行確定這條懸線所在的極大矩陣。底線為 i,j 的懸線 left存每個點能達到的最右位置 right存放每個點能到達的最左邊的位置 height為高度 遞推...
線性dp之懸線法學習筆記
以前寫過求最大正方形面積的題目,這只要處理 i 1 j i j 1 i 1 j 1 三個位置的最小值就可以,用不到懸線法,簡單的線性dp 但是當要求最大長方形時,那種方法就不適合了,懸線法就出現了 模板題 p4147 玉蟾宮 懸線法可以分為三個部分 l i j 代表位置 i,j 可以往左擴充套件的最...
關於懸線法
懸線法的模板題,下面主要講懸線法 懸線法思路 懸線的定義,就是一條豎線,這條豎線要滿足上端點在整個矩形上邊界或者是乙個障礙點。然後以這條懸線進行左右移動,直到移至障礙點或者是矩陣邊界,進而確定這條懸線所在的極大矩陣。具體方法 先預處理 用陣列l,r記錄某點向左和向右能到達的最遠點的縱座標。用陣列up...