2019ICPC银川 K.Largest Common Submatrix(悬线法dp)

该博客讨论了一种解决二维矩阵中寻找最大相同子矩阵面积问题的算法。通过使用悬线法和单调栈,结合矩阵中相邻元素的相对位置判断,实现了在O(n*m)的时间复杂度内找到最大相同子矩阵。代码示例展示了如何实现这一方法。
摘要由CSDN通过智能技术生成
题意:

这里给出两个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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值