洛谷 P1736 创意吃鱼法

链接:https://www.luogu.org/problemnew/show/P1736

这个题真的做的我头大( ⊙ o ⊙ )

题目分析:n行m列的矩阵,非0即1,求满足对角线有鱼(两条对角线其中一条)其他地方无鱼的最大正方形。

思路:二维前缀和;

其实我一开始想的是二维前缀搞出来,然后如果要满足题意的话,n*n的正方形就只能有n条鱼,然后二维前缀和不会打,借助了很多 一点点别的大神的代码,

for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			scanf("%d",&a[i][j]);
			s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
		}

 发现它其实很简单......

再然后,我的最后一个点就被卡的死死的。

也就是说,(3,3)时应为2,但因为(2,2)为2,(3,3)时dp未匹配成功,所以不变。

此时从边长为2的正方形再重新向左上(或右上)扩展,直到匹配不成功,它-1就为当前点的最大正方形。循环次数不会超过它拿来dp的点+1.

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int n,m,maxn1,maxn2,cut;
int dp_num,num,f[2502][2502],s[2502][2502],a[2502][2503];

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            scanf("%d",&a[i][j]);
            s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];//二维前缀和
        }
     for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            int num=f[i-1][j-1]+1;
            dp_num=s[i][j]-s[i-num][j]-s[i][j-num]+s[i-num][j-num];
            if(a[i][j]==1){
                f[i][j]=1;
                if(dp_num==num){
                    f[i][j]=max(f[i][j],num);
                    maxn1=max(maxn1,f[i][j]);
                    continue;
                }
                int cut=2;
                if(dp_num!=num)
                    while(1){
                        num=cut;
                        dp_num=s[i][j]-s[i-num][j]-s[i][j-num]+s[i-num][j-num];
                        if(dp_num==num){
                            f[i][j]=max(f[i][j],num);
                            cut++;
                        }
                        else break;
                    }
                maxn1=max(maxn1,f[i][j]);    
            }
                
        }
    }
    memset(f,0,sizeof(f));
    for(int i=1;i<=n;i++){
        for(int j=m;j>=1;j--){
            if(a[i][j]==1){
                f[i][j]=1;
                int num=f[i-1][j+1];
                dp_num=s[i][j+num]-s[i][j-1]-s[i-num-1][j+num]+s[i-num-1][j-1];
                if(num+1==dp_num&&a[i-1][j+1]==1){
                    f[i][j]=max(f[i][j],num+1);    
                    maxn2=max(maxn2,f[i][j]);
                    continue;;
                }
                cut=2;    
                if(dp_num!=num&&a[i-1][j+1]==1){
                    while(1){
                        num=cut-1;
                        dp_num=s[i][j+num]-s[i][j-1]-s[i-num-1][j+num]+s[i-num-1][j-1];
                        if(num+1==dp_num&&a[i-1][j+1]==1){
                            f[i][j]=max(f[i][j],num+1);    
                            cut++;
                        }
                        else break;    
                    }
                }
            }
            maxn2=max(maxn2,f[i][j]);
        }
    }
    //if(maxn1>maxn2) printf("uiyiuy
");
    printf("%d",max(maxn1,maxn2));
    return 0;
} 

在求从左下到右上对角线时错了

int num=f[i-1][j+1];

  dp_num=s[i][j+num]-s[i][j-1]-s[i-num-1][j+num]+s[i-num-1][j-1];

 我一开始写的是

int num=f[i-1][j+1]+1;
            dp_num=s[i][j+num]-s[i][j]-s[i+num][j+num]+s[i+num][j];

 一开始把要求的正方形的左和上两条边也剪下去了,导致我改了好久qwq

原文地址:https://www.cnblogs.com/jindui/p/11024994.html