最大有效子矩阵

定义:

有效子矩阵:符合条件的子矩阵。

最大有效子矩阵:给定的矩阵中最大的有效子矩阵。

题目就是求最大有效子矩阵有多大?

能用DP写的前提是:最大有效子矩阵中每一个每一个矩阵都为有效矩阵.

见题:

题目显然求的是最大的有效子矩阵(正方形看做特殊的矩阵)。

这里就要讲到一个牛逼的方法,割线法。(我也是今天才学的).

记得以前学过确定最大有效正方形的大小的题,是用f[i][j]表示以点(i,j)最多向左和向右延展多长是有效的正方形。

状态转移:if(...)f[i][j]=min(f[i-1][j],min(f[i-1][j-1],f[j][i-1]))+1;

正方形用一个数组即表示信息,因为边长都相等.

但长方形就不行了,需要用三个数组,left[i][j],right[i][j],up[i][j];

分别表示以点(i,j)向左,向右,向上最大延展的长度.

先上代码:

#include<bits/stdc++.h>
const int maxn=2100;
using namespace std;
int n,m,ans1,ans2;
int l[maxn][maxn],r[maxn][maxn],u[maxn][maxn],a[maxn][maxn];
int main()
{
    freopen("1.in","r",stdin);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) 
        {
            cin>>a[i][j];
            u[i][j]=l[i][j]=r[i][j]=1;//初始化每个点都不能延展,即长度都为1.
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(j==1) continue;
            if(a[i][j]!=a[i][j-1]) l[i][j]+=l[i][j-1];//预处理l数组,
        }
    for(int i=1;i<=n;i++)
        for(int j=m;j>=1;j--)
        {
            if(j==m) continue;
            if(a[i][j]!=a[i][j+1]) r[i][j]+=r[i][j+1];//预处理r数组.
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(i!=1&&a[i][j]!=a[i-1][j])
            {
                l[i][j]=min(l[i][j],l[i-1][j]);
                r[i][j]=min(r[i][j],r[i-1][j]);
                u[i][j]=u[i-1][j]+1;
            }
            int a=l[i][j]+r[i][j]-1;
            int b=u[i][j];
            ans1=max(min(a,b)*min(a,b),ans1);
            ans2=max(ans2,a*b);
        }    
    cout<<ans1<<endl<<ans2<<endl;
    return 0;
}

经过前两个预处理,每个点的l与r数组相加就会有一个长度,而一条枞线上的点就变成了长度不一的线段,那经过这条线的最大矩阵就是线的长度与最短长度的相乘.

我们可以看到在第三个f循坏里,还要更新l和r的信息,我们可以跟着走一遍会发现,这个循环的作用是寻找最短的长度,而抛弃原有的信息,我们可以发现l和r只随i的更新而更新.即随着i的更新,l和r不断寻找最短长度,而与左右的点得l和r的值无关.

 之后以此处理每个矩阵即可。

2:

#include<bits/stdc++.h>
const int maxn=1100;
using namespace std;
int n,m,l[maxn][maxn],r[maxn][maxn],u[maxn][maxn],ans;
char ch[maxn][maxn];
int main()
{
    freopen("1.in","r",stdin);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) 
        {
            cin>>ch[i][j];
            if(ch[i][j]=='F') l[i][j]=r[i][j]=u[i][j]=1;
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(j==1) continue;
            if(ch[i][j]=='F') l[i][j]=l[i][j-1]+1;
        }
    for(int i=1;i<=n;i++)
        for(int j=m;j>=1;j--)
        {
            if(j==m) continue;
            if(ch[i][j]=='F') r[i][j]=r[i][j+1]+1;
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            if(ch[i][j]=='R') continue;
            if(i!=1&&ch[i-1][j]=='F')
            {
                l[i][j]=min(l[i][j],l[i-1][j]);
                r[i][j]=min(r[i][j],r[i-1][j]);
                u[i][j]=u[i-1][j]+1;
            }
            int a=l[i][j]+r[i][j]-1;
            int b=u[i][j];
            ans=max(ans,a*b);
        }
        cout<<ans*3<<endl;
        return 0;
} 

下一题:

#include<bits/stdc++.h>
using namespace std;
#define _ 0
const int maxn=2600;
int m,n,a[maxn][maxn],f[maxn][maxn],s1[maxn][maxn],s2[maxn][maxn],ans;
inline int read()
{
    int x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-') ff=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*ff;
}
inline void put(int x)
{
    if(x<0) putchar('-'),x=-x;
    if(x>9) put(x/10);
    putchar(x%10+'0');
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++) a[i][j]=read();        
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++) 
        {
            if(!a[i][j]) 
            {
                s1[i][j]=s1[i][j-1]+1;
                s2[i][j]=s2[i-1][j]+1;
            }
            if(a[i][j])
            {
                f[i][j]=min(f[i-1][j-1],min(s1[i][j-1],s2[i-1][j]))+1;
                ans=max(ans,f[i][j]);
            }
        }
    }
    memset(f,0,sizeof(f));
    memset(s1,0,sizeof(s1));
    memset(s2,0,sizeof(s2));
    for(int i=1;i<=n;i++)
    {
        for(int j=m;j>=1;j--)
        {
            if(!a[i][j]) 
            {
                s1[i][j]=s1[i][j+1]+1;
                s2[i][j]=s2[i-1][j]+1;
            }
            if(a[i][j])
            {
                f[i][j]=min(f[i-1][j+1],min(s1[i][j+1],s2[i-1][j]))+1;
                ans=max(ans,f[i][j]);
            }
        }
    }
    put(ans);
    return (0^_^0);
}

具体情况具体分析,主要看题目要求的目标矩阵满足的条件设置变量.

转载于:https://www.cnblogs.com/gcfer/p/11404472.html

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值