P1736 创意吃鱼法

中文题

想法:

 借dalao的一张图片

这题其实和之前做过的最大正方形差不多

我们同样定义 f[i][j] 代表以(i,j) 为右下角的符合条件的最大正方形

那么我们怎么进行转移,不难发现这个最大正方形的边长取决于 (i,j)左边连续0的数目,(i,j)上边连续0的数目,以及 f[i-1][j-1]

所以我们可以先预处理出左边连续0的数目,右边连续0的数目

同理,对于以f[i][j] 代表以(i,j)为左下角的符合条件的最大正方形也是采取类似的处理方法

#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <queue>
#include <math.h>
#include <cstdio>
#include <iomanip>
#include <time.h>
#include <bitset>
#include <cmath>
#include <sstream>
#include <iostream>
#include <cstring>

#define LL long long
#define ls nod<<1
#define rs (nod<<1)+1
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define INF 0x3f3f3f3f

const double eps = 1e-10;
const int maxn = 2500 + 10;
const LL mod = 1e9 + 7;

int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;}
using namespace std;

int a[maxn][maxn];
int f[maxn][maxn];
int l[maxn][maxn],r[maxn][maxn],u[maxn][maxn];

int main() {
    ios::sync_with_stdio(false);
    int n,m;
    cin >> n >> m;
    int ans = 0;
    for (int i = 1;i <= n;i++) {
        for (int j = 1;j <= m;j++) {
            cin >> a[i][j];
            if (!a[i][j]) {
                l[i][j] = l[i][j-1] + 1;
                u[i][j] = u[i-1][j] + 1;
            }
            else {
                f[i][j] = min(f[i-1][j-1],min(l[i][j-1],u[i-1][j])) + 1;
            }
            ans = max(ans,f[i][j]);
        }
    }
    for (int i = 1;i <= n;i++) {
        for (int j = m;j >= 1;j--) {
            if (!a[i][j]) {
                r[i][j] = r[i][j+1] + 1;
            }
            else {
                f[i][j] = min(f[i-1][j+1],min(r[i][j+1],u[i-1][j])) + 1;
            }
            ans = max(ans,f[i][j]);
        }
    }
    cout << ans << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/-Ackerman/p/12489486.html