题意:
这里给出两个n*m的矩阵A和B,每个矩阵中的值都是1-nm的排列,问最大相同子矩阵的面积为多少?
注意,相同子矩阵在两个矩阵中的位置可以不同,例:
数据范围:n,m<=1000
解法:
极大子矩阵是经典题了,可以用悬线法或者单调栈来做。
这题的难点在于如何处理子矩阵的位置。
需要想办法判断A中相邻的元素在B中是否相邻。
对于矩阵A中的同一行的相邻元素x和y,
设r1为x在A中的横坐标与x在B中的横坐标差。
c1x在A中的纵坐标与x在B中的纵坐标差。
同理r2,c2为y的在A和B中的横纵坐标差。
如果r1=r2且c1=c2,那么说明在B中,x和y也是相邻的而且相对位置一致。
然后就是普通悬线法了,
两个元素匹配的条件变为两个元素在A和B中的坐标差相同。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e3+5;
struct Node{
int x,y;
}mark[maxm*maxm];
int a[maxm][maxm];
int b[maxm][maxm];
int h[maxm][maxm];
int l[maxm][maxm];
int r[maxm][maxm];
int r1[maxm][maxm];
int c1[maxm][maxm];
int n,m;
signed 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]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&b[i][j]);
}
}
//init
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
mark[b[i][j]]={i,j};
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int x=mark[a[i][j]].x;
int y=mark[a[i][j]].y;
r1[i][j]=i-x;
c1[i][j]=j-y;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
l[i][j]=r[i][j]=j;
h[i][j]=1;
}
}
//dp
for(int i=1;i<=n;i++){
for(int j=2;j<=m;j++){
if(r1[i][j]==r1[i][j-1]&&c1[i][j]==c1[i][j-1]){
l[i][j]=l[i][j-1];
}
}
for(int j=m-1;j>=1;j--){
if(r1[i][j]==r1[i][j+1]&&c1[i][j]==c1[i][j+1]){
r[i][j]=r[i][j+1];
}
}
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(i>=2&&r1[i][j]==r1[i-1][j]&&c1[i][j]==c1[i-1][j]){
h[i][j]=h[i-1][j]+1;
l[i][j]=max(l[i][j],l[i-1][j]);
r[i][j]=min(r[i][j],r[i-1][j]);
}
ans=max(ans,(r[i][j]-l[i][j]+1)*h[i][j]);
}
}
printf("%d\n",ans);
return 0;
}