• 洛谷 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

  • 相关阅读:
    sql
    java常见异常
    call的用法及NodeList与Array的区别
    os模块
    random模块
    time模块
    序列化模块
    模块介绍
    内置函数
    匿名函数-lambda
  • 原文地址:https://www.cnblogs.com/jindui/p/11024994.html
Copyright © 2020-2023  润新知