悬线法用于n*m复杂度找矩阵的最优解。
用l[i][j]表示i,j合法的情况下左边能延伸的坐标,r[i][j]是在右边能延伸的坐标;
up[i][j]是能向上延长的长度;
l,r数组是坐标,up是长度,
题意:给你个n*m矩阵,让你求最大01相间正方形和长方形矩阵。01相间就是相邻两个格子不一样。
这个就是标准的悬线法,求出来以上的数组后,然后以每个i,j为边界,统计答案。
x = r[i][j] - l[i][j] + 1。 这个就是底边。
y = up[i][j]。这个就是宽。
正方形就得取边短的的那个,min(x,y)*min(x,y)。长方形直接x*y。
#include <bits/stdc++.h> #define ll long long #define ull unsigned long long #define met(a, b) memset(a, b, sizeof(a)) #define rep(i, a, b) for(int i = a; i <= b; i++) #define bep(i, a, b) for(int i = a; i >= b; i--) #define pb push_back #define mp make_pair #define debug cout << "KKK" << endl #define ls num*2 #define rs num*2+1 #define re return using namespace std; const ll mod = 998244353; const double PI = acos(-1); const ll INF = 2e18+1; const int inf = 1e9 + 15; const double eps = 1e-7; const int maxn = 2e3 + 5; int l[maxn][maxn], r[maxn][maxn], up[maxn][maxn]; int ma[maxn][maxn]; int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, m; cin >> n >> m; rep(i, 1, n){ rep(j, 1, m){ cin >> ma[i][j]; l[i][j] = r[i][j] = j; up[i][j] = 1; } } rep(i, 1, n){ rep(j, 2, m) if(ma[i][j] + ma[i][j-1] == 1) l[i][j] = l[i][j-1]; bep(j, m-1, 1) if(ma[i][j] + ma[i][j+1] == 1) r[i][j] = r[i][j+1]; } int ans1 = 0, ans2 = 0; rep(i, 1, n){ rep(j, 1, m){ if(i > 1 && ma[i][j] + ma[i-1][j] == 1){ up[i][j] = up[i-1][j] + 1; l[i][j] = max(l[i-1][j], l[i][j]); // 因为是左边能到达的坐标,max越大表示离i越近 r[i][j] = min(r[i-1][j], r[i][j]); // 同上,min越小表示离i越近。 } int x = r[i][j] - l[i][j] + 1; int y = min(x, up[i][j]); ans1 = max(ans1, y*y); ans2 = max(ans2, x*up[i][j]); } } cout << ans1 << ' ' << ans2 << endl; re 0; }