luogu1736_创意吃鱼法_二维dp

题意

简单来说,就是给你一个0/1矩阵,让你找这样一个正方形:一条对角线全是1,其他地方全是0,并使得这个矩阵的边长最大
在这里插入图片描述

solution

  1. 考虑维护一个s1[i][j]表示从(i,j)开始,往上连续0的长度,s2[i][j]表示向左的
  2. 这样向左斜的就这样 f[i][j]=min(f[i-1][j-1],min(s1[i-1][j],s2[i][j-1]))+1;
  3. 向右斜的同理

code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstdlib>
#include<ctime>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
inline int read(){
	char ch=' ';int f=1;int x=0;
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
const int N=3000;
int f[N][N];
int s1[N][N];// up
int s2[N][N];
int a[N][N];
int main()
{
	int n,m;
	n=read();m=read();
	int i,j;
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			a[i][j]=read();
		}
	}
	int ans=0;
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=m;j++)
		{
			if(!a[i][j])
			{
				s1[i][j]=s1[i-1][j]+1;
				s2[i][j]=s2[i][j-1]+1;
			}
			else
			f[i][j]=min(f[i-1][j-1],min(s1[i-1][j],s2[i][j-1]))+1;
			ans=max(ans,f[i][j]);
		}
	}
	memset(s1,0,sizeof(0));
	memset(s2,0,sizeof(0));
	memset(f,0,sizeof(f));
	for(i=1;i<=n;i++)
	{
		for(j=m;j>=1;j--)
		{
			if(!a[i][j])
			{
				s1[i][j]=s1[i-1][j]+1;
				s2[i][j]=s2[i][j+1]+1;
			}
			else
			{
				f[i][j]=min(f[i-1][j+1],min(s1[i-1][j],s2[i][j+1]))+1;
			}
			ans=max(ans,f[i][j]);
		}
	}
	cout<<ans<<endl;
	return 0; 
}


猜你喜欢

转载自blog.csdn.net/qq_42110318/article/details/83796169