2019银川区域赛 K题 Largest Common Submatrix(二维单调栈)

https://nanti.jisuanke.com/t/42391
在这里插入图片描述
题意: 寻找两个矩阵的最大公共子矩阵

思路:
二维单调栈!分为A,B矩阵
横向:先预处理出B矩阵每一行每个格子在A矩阵中向右最多延伸多长。
纵向:知道了纵行每个格子向右的最大延伸,相当于求这个的最大公共矩阵(保证求的时候相连部分是能纵向相连的)
在这里插入图片描述
那么就是m次普通单调栈过程了。
solve()中我是记录了每个格子向左能延伸多长,再单调栈弹出的时候,再加上右边弹出部分的长度,保证这两个部分都不低于这个格子。但是这个写法wa17了
(要是找出了bug希望能告诉我,
我已经wa了50次了┭┮﹏┭┮)。

我tm一定是学了假单调栈。。。

solve2()是我看题解的写法,是通过记录下标来表示有多少格子不低于这个格子,同时不想连的时候,要把stk[0].i处理为i - 1,更新0这个点的位置。

AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 1e3 + 7;
int a[maxn][maxn],b[maxn][maxn];
int h[maxn][maxn];
int ans;
int n,m;

struct Node
{
    int x,y;
}mp1[maxn * maxn + 100],mp2[maxn * maxn + 100];

struct STK
{
    int l;
    int h,i;
}stk[maxn];

void solve(int j)//递增单调栈
{
    int top = 0;
    stk[top].h = 0;stk[top].i = 0;
    mp2[0].x = INF;mp2[0].y = INF;
    h[n + 1][j] = 0;
    int flag = 0;
    for(int i = 0;i <= n + 1;i++)stk[i].l = 0;
    for(int i = 1;i <= n + 1;i++)
    {
        if(mp1[b[i][j]].x == mp1[b[i - 1][j]].x + 1 && mp1[b[i][j]].y == mp1[b[i - 1][j]].y)
            flag = 1;
        else flag = 0;
        int l = 0,len = 0;
        while(top && (stk[top].h > h[i][j] || !flag))
        {
            int s = (stk[top].l + l + 1) * stk[top].h;
            l += stk[top].l + 1;
            ans = max(ans,s);
            top--;
        }
        stk[++top].h = h[i][j];stk[top].i = i;
        if(flag)stk[top].l = l;
        else if(!flag)stk[top].l = 0;
    }
}

void solve2(int j)
{
    int top = 0;
    stk[top].h = 0;stk[top].i = 0;
    mp2[0].x = INF;mp2[0].y = INF;
    h[n + 1][j] = 0;
    int flag = 0;
    for(int i = 0;i <= n + 1;i++)stk[i].l = 0;
    for(int i = 1;i <= n + 1;i++)
    {
        if(mp1[b[i][j]].x == mp1[b[i - 1][j]].x + 1 && mp1[b[i][j]].y == mp1[b[i - 1][j]].y)
            flag = 1;
        else flag = 0;
        while(top && (stk[top].h > h[i][j] || !flag))
        {
            int s = (i - 1 - stk[top - 1].i) * stk[top].h;
            ans = max(ans,s);
            top--;
        }
        stk[++top].h = h[i][j];stk[top].i = i;
        if(!flag)stk[0].i = i - 1;
    }
}

int 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]);
            mp1[a[i][j]].x = i;
            mp1[a[i][j]].y = j;
        }
    }
    
    for(int i = 1;i <= n;i++)
    {
        for(int j = 1;j <= m;j++)
        {
            scanf("%d",&b[i][j]);
            mp2[b[i][j]].x = i;mp2[b[i][j]].y = j;
        }
    }
    
    for(int i = 1;i <= n;i++)
    {
        for(int j = 1;j <= m;j++)
        {
            if(mp1[b[i][j]].x == mp1[b[i][j - 1]].x && mp1[b[i][j]].y == mp1[b[i][j - 1]].y + 1)
            {
                h[i][j] = h[i][j - 1] + 1;
            }
            else h[i][j] = 1;
        }
    }
    
    for(int i = 1;i <= m;i++)
    {
        solve(i);
    }
    
    printf("%d\n",ans);
    return 0;
}




BUG代码

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int INF = 0x3f3f3f3f; 
const int maxn = 1e3 + 7;
int a[maxn][maxn],b[maxn][maxn];
int h[maxn][maxn];
int ans;
int n,m;

struct Node
{
    int x,y;
}mp1[maxn * maxn + 100],mp2[maxn * maxn + 100];

struct STK
{
    int l;
    int h,i;
}stk[maxn];

void solve(int j)//递增单调栈
{
    int top = 0;
    stk[top].h = 0;stk[top].i = 0;
    mp2[0].x = INF;mp2[0].y = INF;
    h[n + 1][j] = 0;
    int flag = 0;
    for(int i = 0;i <= n + 1;i++)stk[i].l = 0;
    for(int i = 1;i <= n + 1;i++)
    {
        if(mp1[b[i][j]].x == mp1[b[i - 1][j]].x + 1 && mp1[b[i][j]].y == mp1[b[i - 1][j]].y)
            flag = 1;
        else flag = 0;
        int l = 0,len = 0;
        while(top && (stk[top].h > h[i][j] || !flag))
        {
            int s = (stk[top].l + l + 1) * stk[top].h;
            l++;
            ans = max(ans,s);
            len = stk[top].l;
            top--;
        }
        stk[++top].h = h[i][j];stk[top].i = i;
        if(flag)stk[top].l = l + len;
        else if(!flag)stk[top].l = 0;
    }
}

void solve2(int j)
{
    int top = 0;
    stk[top].h = 0;stk[top].i = 0;
    mp2[0].x = INF;mp2[0].y = INF;
    h[n + 1][j] = 0;
    int flag = 0;
    for(int i = 0;i <= n + 1;i++)stk[i].l = 0;
    for(int i = 1;i <= n + 1;i++)
    {
        if(mp1[b[i][j]].x == mp1[b[i - 1][j]].x + 1 && mp1[b[i][j]].y == mp1[b[i - 1][j]].y)
            flag = 1;
        else flag = 0;
        while(top && (stk[top].h > h[i][j] || !flag))
        {
            int s = (i - 1 - stk[top - 1].i) * stk[top].h;
            ans = max(ans,s);
            top--;
        }
        stk[++top].h = h[i][j];stk[top].i = i;
        if(!flag)stk[0].i = i - 1;
    }
}

int 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]);
            mp1[a[i][j]].x = i;
            mp1[a[i][j]].y = j;
        }
    }
    
    for(int i = 1;i <= n;i++)
    {
        for(int j = 1;j <= m;j++)
        {
            scanf("%d",&b[i][j]);
            mp2[b[i][j]].x = i;mp2[b[i][j]].y = j;
        }
    }
    
    for(int i = 1;i <= n;i++)
    {
        for(int j = 1;j <= m;j++)
        {
            if(mp1[b[i][j]].x == mp1[b[i][j - 1]].x && mp1[b[i][j]].y == mp1[b[i][j - 1]].y + 1)
            {
                h[i][j] = h[i][j - 1] + 1;
            }
            else h[i][j] = 1;
        }
    }
    
    for(int i = 1;i <= m;i++)
    {
        solve2(i);
    }
    
    printf("%d\n",ans);
    return 0;
}



发布了628 篇原创文章 · 获赞 17 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/104035187