• hihocoder1580 Matrix


    题目链接:(vjudge)戳我

    从今天开始不咕咕地填坑啦

    考虑一般的求最大子矩阵和。。。我们一般都是DP,或者直接上悬线法递推。

    下面附一个DP的代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define MAXN 310
    using namespace std;
    int n,m,p,all,ans;
    int a[MAXN][MAXN],dp[MAXN],minn[MAXN],sum[MAXN];
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        while(scanf("%d%d%d",&n,&m,&p)!=EOF)
        {
            memset(a,0,sizeof(a));
            memset(dp,0,sizeof(dp));
            memset(minn,0x3f,sizeof(minn));
            all=0,ans=-2147483647;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    scanf("%d",&a[i][j]),all+=a[i][j];
            for(int l=1;l<=n;l++)
            {
                memset(sum,0,sizeof(sum));
                for(int r=l;r<=n;r++)
                {
                    for(int i=1;i<=m;i++)
                    {
                        sum[i]+=a[r][i];
                        if(l==r) minn[i]=a[r][i];
                            else minn[i]=min(minn[i],a[r][i]);
                        if(i==1) dp[i]=sum[i];
                            else dp[i]=max(sum[i],dp[i-1]+sum[i]);
                        ans=max(ans,dp[i]);
                    }
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    

    然后这个题就是最大子矩阵和的变形。要求必须修改一个。

    我们新开一个数组dp2[i]来记录第一维在([l,r])范围内(这个做右端点是需要(n^2)枚举的),第二维计算到i的时候,修改了一个位置为p的最大子矩阵和。

    因为要修改之后尽量大,所以我们转移的时候需要维护当前(i)这一列最小的矩形中最小的元素,那么带修改的自然就是减去这个最小值然后加上p了。

    转移最大子矩形和的时候注意分类讨论,分一类为继承前一列,一类为自己新开一个。带修改的还需要分类讨论如果继承前一列,那个带修改的位置到底是在自己这一列还是在前面列中。

    然后还有一点就是因为我们修改的这个位置不一定被选入到我们的最大子矩阵和的矩阵里,所以每个不修改的状态也要记录一遍。(当然要特判一下,所有数取满是非法情况要排除掉啦!)

    然后每种情况都和ans取一个最大值。

    具体看代码吧。代码如下:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define MAXN 310
    using namespace std;
    int n,m,p,all,ans;
    int a[MAXN][MAXN],dp1[MAXN],dp2[MAXN],minn[MAXN],sum[MAXN];
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("ce.in","r",stdin);
        #endif
        while(scanf("%d%d%d",&n,&m,&p)!=EOF)
        {
            memset(a,0,sizeof(a));
            memset(dp1,0,sizeof(dp1));
            memset(dp2,0,sizeof(dp2));
            memset(minn,0x3f,sizeof(minn));
            all=0,ans=-2147483647;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    scanf("%d",&a[i][j]),all+=a[i][j];
            for(int l=1;l<=n;l++)
            {
                memset(sum,0,sizeof(sum));
                for(int r=l;r<=n;r++)
                {
                    for(int i=1;i<=m;i++)
                    {
                        sum[i]+=a[r][i];
                        if(l==r) minn[i]=a[r][i];
                            else minn[i]=min(minn[i],a[r][i]);
                        if(i==1) dp1[i]=sum[i];
                            else dp1[i]=max(sum[i],dp1[i-1]+sum[i]);
                        if(i==1) dp2[i]=sum[i]-minn[i]+p;
                            else dp2[i]=max(dp2[i-1]+sum[i],max(dp1[i-1]+sum[i]-minn[i]+p,sum[i]-minn[i]+p));
                        if(dp1[i]!=all) 
                        ans=max(ans,dp1[i]);
                        ans=max(ans,dp2[i]);
                        printf("l=%d r=%d i=%d ans=%d
    ",l,r,i,ans);
                    }
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    MVC5个人用户账户身份验证集成google和facebook的OAuth2登陆
    2016.8.5
    2016.7.29
    2016.7.25
    如何将返回的JSon字符串用MAP格式读取
    代码里获得系统时间写法
    Mybatis中<![cdata[ ]]>
    Orcal语法Merge into用法
    Page.IsPostBack属性
    Android之打开闪光灯关键代码
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10347270.html
Copyright © 2020-2023  润新知