【解题报告】luogu P1736 创意吃鱼法(多维dp)

原题链接

题意

给一个n×m的仅有0或者1组成的矩形矩阵,要求一正方形子矩阵,保证该矩阵有一条对角线上的元素全为1,其余元素全为0,求满足条件的子矩阵中对角线长度最大的子矩阵的对角线长度为多少

思路

该题目和另外一个dp题目很类似:
P1387 最大正方形
我们要求最大的子矩阵,采取的是递推的思想,设f[i][j]表示以i为横坐标,j为纵坐标的点为右下角的满足条件的子矩阵的对角线长度,那么很容易得到,我们可以用f[i-1][j-1]即该坐标的斜上方的子矩阵的对角线长度+1得到f[i][j]。但这个推法存在一个问题,无法保证其余的元素全为0。所以我们要另外开两个数组,一个用来装该坐标点左(右)边连续0的长度,一个用来装该坐标点下边连续0的长度,然后我们取这两个长度和f[i-1][j-1]这三者的最小值来+1作为f[i][j]。才能得到正确的答案。
注:由于正方形存在两条对角线,所以需要遍历两遍,一次从左上到右下,一次从右上到左下。

上代码:

#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
int dp[2505][2505];
int map[2505][2505];
int c[2505][2505];
int r[2505][2505];
int main()
{
    #ifdef _DEBUG
    freopen("/home/jiengupxing/Downloads/testdata (3).in", "r", stdin);
    #endif
    int n, m;
    int ans = 0;
    cin>>n>>m;
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            cin>>map[i][j];
        }
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            if(map[i][j] == 0)
            {
                c[i][j] = c[i-1][j]+1;
                r[i][j] = r[i][j-1]+1;
            }
            else
            {
                dp[i][j] = min(min(c[i-1][j], r[i][j-1]), dp[i-1][j-1])+1;
                ans = max(ans, dp[i][j]);
            }
        }
    }
    memset(c, 0, sizeof(c));
    memset(r, 0, sizeof(r));
    memset(dp, 0, sizeof(dp));
    for(int i=1; i<=n; i++)
    {
        for(int j=m; j>=1; j--)
        {
            if(map[i][j] == 0)
            {
                c[i][j] = c[i-1][j]+1;
                r[i][j] = r[i][j+1]+1;
            }
            else
            {
                dp[i][j] = min(min(c[i-1][j], r[i][j+1]), dp[i-1][j+1])+1;

            }
            ans = max(ans ,dp[i][j]);
        }
    }
    cout<<ans;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42772300/article/details/88427554