洛谷1169:棋盘制作(悬线法)

洛谷1169:棋盘制作(悬线法)

悬线法:

用于解决给定矩阵满足条件的最大子矩阵。

做法:

用一条线(横竖都行)左右移动直到不满足约束条件或者到达边界。

定义:

\(left(i,j)\):表示\((i,j)\)向左扩展能够到达的最左边的位置。

\(right(i,j)\):表示\((i,j)\)向右扩展能够到达的最右边的位置。

\(up(i,j)\):表示\((i,j)\)向上能够拓展的最长长度。

递推公式:

\(left(i,j)=max\{left(i,j),left(i-1,j)\}\).

\(right(i,j)=min(right(i,j),right(i-1,j))\).

因为有\(up\)数组,\(up\)数组表示向上拓展的最长长度,所以要考虑上一层的情况。

#include
using namespace std;
const int maxn = 2e3 + 10;
int a[maxn][maxn], n, m;
int lef[maxn][maxn];
int rig[maxn][maxn];
int up[maxn][maxn];


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]);
            lef[i][j] = rig[i][j] = j;
            up[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])
                lef[i][j] = lef[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])
                rig[i][j] = rig[i][j+1];
    }

    int ans1, ans2;
    ans1 = 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])
        {
            lef[i][j] = max(lef[i][j], lef[i-1][j]);
            rig[i][j] = min(rig[i][j], rig[i-1][j]);
            up[i][j] = up[i-1][j]+1;
        }
        int a = rig[i][j] - lef[i][j] + 1;
        int b = up[i][j];
        ans1 = max(ans1, min(a,b)*min(a,b));//Õý·½ÐÎ
        ans2 = max(ans2, a*b);
    } cout << ans1 << endl << ans2 << endl;
    return 0;
}

你可能感兴趣的:(洛谷1169:棋盘制作(悬线法))