懸線法
介紹
可以用來解決最大子矩陣問題
原理分析
設L/R[i][j]表示自點(i,j)向左/右在不經過障礙點情況下能達到的最遠點橫坐標(圖是數組畫法時的橫坐標),up[i][j]表示(i,j)向上能達到的最遠點,初始化為up[i][j] = 1;R[i][j] = L[i][j] = j;得到的是(R-L+1) * up的一個矩陣,如果上面也是合法矩形,那么就合並兩個矩形更新答案。但是是否不合並更好呢?當然可能,不過這種情況下上下兩矩形的(R - L + 1)不同,在不接合的點會考慮此情況。
例題
Luogu-P4147
#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<cstring>
#include<algorithm>
#define lson x<<1
#define rson x<<1|1
#define ll long long
#define rint register int
#define mid ((L + R) >> 1)
using namespace std;
template <typename xxx> inline void read(xxx &x) {
char c = getchar(),f = 1;x = 0;
for(;c ^ '-' && !isdigit(c);c = getchar());
if(c == '-') c = getchar(),f = -1;
for(;isdigit(c);c = getchar()) x = (x<<1) + (x<<3) + (c ^ '0');
x *= f;
}
template<typename xxx>void print(xxx x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
const int maxn = 2010;
const int inf = 0x7fffffff;
const int mod = 1e9 + 7;
char s[maxn];
int a[maxn][maxn];
int R[maxn][maxn];//表示從(i,j)這個點出發向右能到達最遠的點橫坐標
int L[maxn][maxn];//表示從(i,j)這個點出發向左能到達最遠的點橫坐標
int up[maxn][maxn];//向上到達最遠點的距離
int n,m;
int main() {
int ans = 0;
read(n);read(m);
for(rint i = 1;i <= n; ++i) {
for(rint j = 1;j <= m; ++j) {
scanf("%s",s);
if(s[0] == 'F') a[i][j] = 1;
up[i][j] = 1;
R[i][j] = L[i][j] = j;
}
}
for(rint i = 1;i <= n; ++i) {
for(rint j = 2;j <= m; ++j) {
if(a[i][j] && a[i][j - 1]) {
L[i][j] = L[i][j - 1];
}
}
}
for(rint i = 1;i <= n; ++i) {
for(rint j = m - 1; j; --j) {
if(a[i][j] && a[i][j + 1]) {
R[i][j] = R[i][j + 1];
}
}
}
for(rint i = 1;i <= n; ++i) {
for(rint j = 1;j <= m; ++j) {
if(i > 1) {
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]);
}
}
print(ans * 3);
return 0;
}
/*
*/
枚舉障礙點法???
簡介
如果方格圖過大又不便離散化,且障礙點很少,那么此法更優。
原理分析
參見淺談用極大化思想解決最大子矩形問題--王知昆,注意,部分有誤。
例題
Luogu-P1578
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <bitset>
#define Max(a,b) (a>b?a:b)
#define Min(a,b) (a<b?a:b)
#define ll long long
#define rint register int
#define mid ((L + R) >> 1)
#define lson (x << 1)
#define rson (x << 1 | 1)
using namespace std;
template<typename xxx>inline void read(xxx &x) {
x = 0;int f = 1;char c = getchar();
for(;c ^ '-' && !isdigit(c);c = getchar());
if(c == '-') f = -1,c = getchar();
for(;isdigit(c);c = getchar()) x = (x << 3) + (x << 1) + (c ^ '0');
x *= f;
}
template<typename xxx>inline void print(xxx x) {
if(x < 0) {
putchar('-');
x = -x;
}
if(x > 9) print(x / 10);
putchar(x % 10 + '0');
}
const int maxn = 100010;
const int mod = 1e9 + 7;
const int inf = 0x7f7f7f7f;
struct node{
int xi,yi;
}g[maxn];
inline bool gmp1(node a,node b) {
if(a.xi == b.xi) return a.yi < b.yi;
return a.xi < b.xi;
}
inline bool gmp2(node a,node b) {
if(a.yi == b.yi) return a.xi < b.xi;
else return a.yi < b.yi;
}
int n,L,W,ans;
int main() {
read(L);read(W);read(n);
for(rint i = 1;i <= n; ++i) {
read(g[i].xi);
read(g[i].yi);
}
++n;g[n] = (node){0,0};
++n;g[n] = (node){L,W};
++n;g[n] = (node){0,W};
++n;g[n] = (node){L,0};
stable_sort(g + 1,g + n + 1,gmp1);
for(rint i = 1;i <= n; ++i) {
int up = W,d = 0;
for(rint j = i + 1;j <= n; ++j) {
ans = Max(ans,(g[j].xi - g[i].xi) * (up - d));
if(g[j].yi < g[i].yi) d = Max(d,g[j].yi);
else up = Min(g[j].yi,up);
}
}
for(rint i = n; i; --i) {
int up = W,d = 0;
for(rint j = i - 1; j; --j) {
ans = Max(ans,(g[i].xi - g[j].xi) * (up - d));
if(g[j].yi < g[i].yi) d = Max(d,g[j].yi);
else up = Min(g[j].yi,up);
}
}
stable_sort(g + 1,g + n + 1,gmp2);
for(rint i = 2;i <= n; ++i) {
ans = Max(ans,(g[i].yi - g[i - 1].yi) * L);
}
print(ans);
}
/*
4 7
5
0 6
0 0
3 2
1 0
0 3
21
10 10
2
8 1
3 9
80
10 10
3
3 0
8 2
3 9
72
5 5
3
1 3
3 1
3 4
12
10 10
6
1 2
3 2
6 2
2 1
2 3
2 5
64
*/