博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
有关最大子矩阵的说明
阅读量:4355 次
发布时间:2019-06-07

本文共 4747 字,大约阅读时间需要 15 分钟。

很久以前,我做过一些最大子矩阵的问题,当时用的是悬线法,这是一个有意思的算法,举例:

(码风稍微有些奇怪,毕竟这是很久以前做的了,忍忍吧)

悬线法的重点在于处理出将每一个点可以向两边扩展的最远位置,再从上到下求出每个点可以向上扩展的位置。

算法复杂度为\(O_{nm}\),常数有点大。

#include
using namespace std;int n,m;int a[1001][1001],l[1001][1001],r[1001][1001],h[1001][1001];int main(){ cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { cin>>a[i][j]; l[i][j]=r[i][j]=j; h[i][j]=1; } for(int i=1;i<=n;i++) for(int j=2;j<=m;j++) if(a[i][j]!=a[i][j-1]) l[i][j]=l[i][j-1]; for(int i=1;i<=n;i++) for(int j=m-1;j>=1;j--) if(a[i][j]!=a[i][j+1]) r[i][j]=r[i][j+1]; int ans1=0,ans2=0; 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]=max(l[i][j],l[i-1][j]); r[i][j]=min(r[i][j],r[i-1][j]); h[i][j]=h[i-1][j]+1; } int a=r[i][j]-l[i][j]+1; int b=min(a,h[i][j]); ans1=max(ans1,b*b); ans2=max(ans2,a*h[i][j]); } cout<
<
<

然而今天在做到时,很显然我写了个悬线法,光荣的获得了\(TLE\)……

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;const int N=1010;int n,m,ans,num[N][N];char las[N][N],now[N][N];int l[N][N][3],r[N][N][3],h[N][N][3];inline int max(int a,int b) {return a>b?a:b;}inline void Change(int p){ for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) if(p==0&&(las[i][j]=='w'||las[i][j]=='y'||las[i][j]=='z')) now[i][j]='a'; else if(p==1&&(las[i][j]=='w'||las[i][j]=='x'||las[i][j]=='z')) now[i][j]='b'; else if(p==2&&(las[i][j]=='x'||las[i][j]=='y'||las[i][j]=='z')) now[i][j]='c'; memset(num,0,sizeof(num)); for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) if(now[i][j]=='a'&&p==0) num[i][j]=1; else if(now[i][j]=='b'&&p==1) num[i][j]=1; else if(now[i][j]=='c'&&p==2) num[i][j]=1;}inline void Dangle(int p){ for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) l[i][j][p]=r[i][j][p]=j,h[i][j][p]=1; for(register int i=1;i<=n;i++) for(register int j=2;j<=m;j++) if(num[i][j]==num[i][j-1]) l[i][j][p]=l[i][j-1][p]; for(register int i=1;i<=n;i++) for(register int j=m-1;j>=1;j--) if(num[i][j]==num[i][j+1]) r[i][j][p]=r[i][j+1][p]; for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) { if(i>1&&num[i][j]==num[i-1][j]) { l[i][j][p]=max(l[i-1][j][p],l[i-1][j][p]); r[i][j][p]=min(r[i-1][j][p],r[i-1][j][p]); h[i][j][p]=h[i-1][j][p]+1; } ans=max(ans,(l[i][j][p]-r[i][j][p]+1)*h[i][j][p]); }}int main(){ while(scanf("%d%d",&n,&m)!=EOF) { for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) cin>>las[i][j],now[i][j]=las[i][j]; ans=-1;for(register int i=0;i<=n;i++) Change(i),Dangle(i); printf("%d\n",ans); }}/*for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) cout<

说实话,这很让我蒙,上网一查,很多人用的是单调栈,好像这两种做法的区别不大,都可以做这一题。

后来发现了王知昆\(Dalao\)的。里面谈到这两种算法的复杂度有较大区别。原话如下:

以上说了两种具有一定通用性的处理算法,时间复杂度分别为\(O_{S^2}\)\(O_{nm}\) 。两种算法分别适用于不同的情况。从时间复杂度上来看,第一种算法对于障碍点稀疏的情况比较有效,第二种算法则与障碍点个数的多少没有直接的关系(当然,障碍点较少时可以通过对障碍点坐标的离散化来减小处理矩形的面积,不过这样比较麻烦,不如第一种算法好),适用于障碍点密集的情况。

好像有点道理,于是我又将这一题改为了如下的样子:

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;const int N=1010;char las[N][N],now[N][N];int n,m,ans,num[N][N],H[N],top,w[N];inline int max(int a,int b) {return a>b?a:b;}inline bool Check1(int i,int j){return las[i][j]=='w'||las[i][j]=='y'||las[i][j]=='z';}inline bool Check2(int i,int j){return las[i][j]=='w'||las[i][j]=='x'||las[i][j]=='z';}inline bool Check3(int i,int j){return las[i][j]=='x'||las[i][j]=='y'||las[i][j]=='z';}inline void Change(int p){ for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) { num[i][j]=0; if(p==0&&(Check1(i,j)||las[i][j]=='a')) num[i][j]=num[i-1][j]+1; else if(p==1&&(Check2(i,j)||las[i][j]=='b')) num[i][j]=num[i-1][j]+1; else if(p==2&&(Check3(i,j)||las[i][j]=='c')) num[i][j]=num[i-1][j]+1; else num[i][j]=num[i-1][j]; } /*for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) cout<
H[top]) H[++top]=num[i][j],w[top]=1; else { int wid=0; while(num[i][j]
0) { for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) cin>>las[i][j],now[i][j]=las[i][j]; ans=-1;for(register int i=0;i<=n;i++) Change(i),Dangle(i); printf("%d\n",ans); }}/*for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) cout<

具体思路是将每一行的\(1\)压下来,再按最大子段和来做,但还是\(TLE\)……那是真的爽

后来发现一个很有趣的地方,好像内存大了会\(TLE\)?

再仔细看一下网上的做法,总体思路没太大问题,还是像悬线一样求\(l,r\),但有人用单调栈求,有人用跳。

先咕着……

转载于:https://www.cnblogs.com/wo-shi-zhen-de-cai/p/10959579.html

你可能感兴趣的文章
【转】globk和glorg中使用的apr文件
查看>>
导航,头部,CSS基础
查看>>
PostMessage 解析
查看>>
Java语法基础(一)
查看>>
as3 sort
查看>>
hdu 2680 Choose the best route Dijkstra 虚拟点
查看>>
26. Remove Duplicates from Sorted Array java solutions
查看>>
[bzoj1185] [HNOI2007]最小矩形覆盖
查看>>
全景图制作详解
查看>>
React之todo-list
查看>>
cocoapods降级版本
查看>>
MYSQL复习笔记4-基本SQL语句
查看>>
C#&java重学笔记(函数)
查看>>
14软件G2班
查看>>
bzoj 1977 [BeiJing2010组队]次小生成树 Tree
查看>>
bzoj 2119 股市的预测——枚举长度的关键点+后缀数组
查看>>
maven:新建的maven工程需要添加一下插件
查看>>
改变和恢复view的方向
查看>>
C#调用金数据API
查看>>
Convert Sorted List to Binary Search Tree
查看>>