顧名思義,就是從每乙個點(或者邊界)開始,以此為邊界,開始像用一根豎線一樣不斷移動,在遇到障礙點或邊界時確定出極大子矩陣。
核心內容就是確定一條邊界,不斷擴充套件並修改其他邊界
可能有點抽象,做題理解一下就好。
在 wzk 大佬的國家隊****用極大化思想解決最大子矩陣問題中有詳細的講解
從題目入手講解
本人在洛谷建了乙個有關懸線法的題單,可以拿這些題入門-->懸線法合集
點我點我
#include#include#include#include#define r register
#define n 2020
using namespace std;
inline int read()
while(ch>='0'&&ch<='9')
return x*f;
}int n,m,a[n][n],l[n][n],r[n][n],up[n][n];//l,r代表每個點向左(右)擴充套件到的最遠位置,up表示向上擴充套件的高度
int ans1,ans2;
int main()
for(r int i = 1;i <= n;i++)
} for(r int i = 1;i <= n;i++)
} for(r int i = 1;i <= n;i++)
int length = r[i][j]-l[i][j]+1;
int width = min(length,up[i][j]) ;
ans1 = max(ans1,width*width);
ans2 = max(ans2,length*up[i][j]);
} }printf("%d\n%d\n",ans1,ans2);
return 0;
}
點我點我
#include#include#include#include#define n 5010
#define r register
using namespace std;
inline int read()
while(ch>='0'&&ch<='9')
return x*f;
}int l,w,n,ans;
struct dataa[n];
inline bool cmp1(data a,data b)
inline bool cmp2(data a,data b)
int main(),a[++n] = data,a[++n] = data,a[++n] = data;//人為加點
sort(a+1,a+1+n,cmp1);
for(r int i = 1;i <= n;i++)
if(a[j].y>a[i].y)up = min(up,a[j].y);//更新上下界
else down = max(down,a[j].y);
}} if(!flag)ans = max(ans,len*(up-down));//如果中途退出就不能再更新了,因為上下界沒有更新完
up = w,down = 0,len = a[i].x,flag = 0;//向左掃,同理
for(r int j = i-1;j;j--)
if(a[j].y>a[i].y)up = min(up,a[j].y);
else down = max(down,a[j].y);
}} if(!flag)ans = max(ans,len*(up-down));
} sort(a+1,a+1+n,cmp2);//上面說的左右邊界均在牛場邊界的情況
for(r int i = 1;i < n;i++)ans = max(ans,(a[i+1].y-a[i].y)*l);
printf("%d\n",ans);
return 0;
}
懸線法(解決最大子矩陣型別的問題)
顧名思義 懸線法就如條懸著的線一般 先定義幾樣東西 定義子矩形 有效子矩形 內部不包含障礙點的 輪廓與整個矩形平行或重合的子矩形 極大子矩形 每條邊都不能向外擴充套件的有效子矩形。最大子矩形 所有有效子矩形中最大的乙個 或多個 我們可以很顯然的看出 乙個子矩陣要最大,那麼這個子矩陣一定不能再向上,下...
懸線法DP總結
求滿足某種條件 如01交替 的最大矩形 正方形 先預處理出 ml i j mr i j mt i j 分別表示當前位置 i,j 能向左擴充套件到的最左邊的編號 能向右擴充套件到的最右邊的編號 能向上擴充套件到的最大高度。然後在做 dp 時,除第一行,每行根據上一行的狀態更新當前狀態,逐行掃一遍。複雜...
ACM 懸線法總結
一般分為兩種做法 有乙個n m的矩陣,初始為白色,裡面有s個黑色格仔,現在問能在矩陣裡面找到的最大不包含 黑色格仔的子矩陣 正方形 n,m 1000,s n m 例題 p2701 usaco5.3 巨大的牛棚big barn 農夫約翰想要在他的正方形農場上建造一座正方形大牛棚。他討厭在他的農場中砍樹...