1. 程式人生 > >luogu1736_創意吃魚法_二維dp

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; 
}