算法用处
\(\quad\)可以解决图中满足条件的最大子矩阵的问题。
算法原理
\(\quad\)悬线法,悬线的定义,就是一条竖线,这条竖线要满足上端点在整个矩形上边界或者是一个障碍点。然后以这条悬线
\(\quad\)进行左右移动,直到移至障碍点或者是矩阵边界,进而确定这条悬线所在的极大矩阵。也就是说,我们要针对矩阵中每个点进行求极大矩阵的操作。
做法
\(\quad\)理性上讲就是枚举每一个点可到达的满足条件的最左端和最右端和最上端,最后得出最大值。
\(\quad\)感性的想就是一根线,拉直了分别往左右上探探,以此探到最大值。
定义
l[i][j]//(i,j) 能够满足条件的左边的最值的纵坐标
r[i][j]//(i,j) 能够满足条件的右边的最值的纵坐标
up[i][j]//(i,j) 能够满足条件的上面的最值的横坐标
递推公式
Up:Up[i][j] = Up[i-1][j] + 1
Right:min(R[i][j],R[i-1],[j])
Left::max(L[i][j],L[i-1][j])
时间复杂度:\(O(m\times n)\)
例题
\(\quad\)其实不难发现这题就是一个求最大矩阵问题,而这个数据规模也不算很大,就可以用我们的悬线法啦。
\(\quad\)做法上面已经讲了,下面贴出代码(代码里会再次解释)
#include<bits/stdc++.h>
#define fo(i,j,k) for(register int i=j;i<=k;i++)
#define fd(i,j,k) for(register int i=j;i>=k;i--)
#define ll long long
#define re register
#define file(x) freopen("x.in.txt","r",stdin);freopen("x.out.txt","w",stdout);
#define ios ios::sync_with_stdio(false)
using namespace std;
inline int Readc(){
char c=getchar();
while(c!='R'&&c!='F')c=getchar();
if(c=='F')return 1;
return 0;
}//快读(应该比较好理解吧)
int n,m,ans1,ans,mp[1001][1001];
int l[2018][2018],r[2018][2018];
int up[2018][2018];
int main()
{
ans=0;
cin>>n>>m;
fo(i,1,n)
fo(j,1,m)
{
mp[i][j]=Readc();
l[i][j]=j;
r[i][j]=j;
up[i][j]=1;
}//输入和l,r,up数组的初始化
fo(i,1,n)
fo(j,2,m)
{
if(mp[i][j]=1 && mp[i][j-1]=1)//需要满足的条件
l[i][j]=l[i][j-1];//如果满足了它的最左就等于它左端的最左
}
fo(i,1,n)
fd(j,m-1,1)//此处强调必须从右到左,因为是运用了dp的思想所以要从小到大递推
{
if(mp[i][j]=1 && mp[i][j+1]=1)//需要满足的条件
r[i][j]=r[i][j+1];//如果满足了它的最右就等于它右端的最右
}
fo(i,1,n)
fo(j,1,m)//枚举每个点,统计答案最大值
{
if(i>1 && mp[i][j]=1 && mp[i-1][j]=1)
{
r[i][j]=min(r[i][j],r[i-1][j]);//矩阵是个规则图形所以也要考虑上面的部份,总不能是歪歪扭扭的,所以此处还需再次更新一边最值
l[i][j]=max(l[i][j],l[i-1][j]);//与上面同理
up[i][j]=up[i-1][j]+1;//此处也在统计上面的最值
}
ans=max(ans,(r[i][j]-l[i][j]+1)*up[i][j]);//答案统计,中间公式应该很好理解就不说了
}//最后运算答案
cout<<ans*3;//输出
//完美谢幕
return 0;
}