2019年ACM银川站H题_悬线法

Posted 一只特立独行的猫

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019年ACM银川站H题_悬线法相关的知识,希望对你有一定的参考价值。


原题链接.

题目大意:
给定两个n*m的矩阵,求他们的最大公共子矩阵,并输出这个子矩阵中的元素个数。
所以输出4。
思路:
采用悬线法

悬线法用来求直方图中最大矩形的面积。在直方图的每个柱体顶端悬挂一根线,然后将线左右移动,并分别记录该移动的最左端和最右端。左右两端的长度再乘以高度,就是当前柱体可以形成的最大面积。

上图需要将两个矩阵预处理成一个矩阵,这个矩阵只存储第二个矩阵的数字在第一个矩阵中的位置。然后就可以通过判断b[i][j] - b[i-1][j]==m来确定上下是否相连。判断b[i][j]-b[i][j-1]==1来判断左右是否相连。抽象为了一个直方图问题。

#include<iostream>
#include<cstdio>

using namespace std;

const int N = 1e3 + 5;

//a数组存储第一个矩阵,b存储映射矩阵,temp用来存储映射关系
int a[N][N], b[N][N],temp[N*N];
int n, m;
//c数组存储直方图的高度
int c[N],L[N],R[N],sum;

void solve() {
	int ans = 0;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (b[i][j] - b[i - 1][j] == m && i != 1) {
				c[j] = c[j]+1;
			}
			else {
				c[j] = 1;
			}
			L[j] = j;
			R[j] = j;
		}
		for (int j = 1; j <= m; j++) {
			//左端点
			while (L[j] != 1 && c[j] <= c[L[j] - 1] && b[i][j] - b[i][L[j] - 1] == j - L[j] + 1) L[j] = L[L[j] - 1];
		}
		for (int j = m; j >0; j--) {
			//右端点
			while (R[j] != m && c[j] <= c[R[j] + 1] && b[i][j] - b[i][R[j] + 1] == j - R[j] - 1) R[j] = R[R[j] + 1];
		}
		for (int j = 1; j <= m; j++) {
			sum = (R[j]-L[j]+1) * c[j];
			ans = max(ans, sum);
		}
	}
	cout << ans << endl;
}

int main() {
	int k = 1;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			scanf("%d", &a[i][j]);
			//记录出现的相对位置
			temp[a[i][j]] = k++;
		}
	}
	int x;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			scanf("%d", &x);
			//提取两个矩阵的特征
			b[i][j] = temp[x];
		}
	}
	solve();
	return 0;
}

以上是关于2019年ACM银川站H题_悬线法的主要内容,如果未能解决你的问题,请参考以下文章

HDU 6957 Maximal submatrix(悬线法 || 优先队列 || 单调栈 )

2004-2005 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2004)

bzoj3039玉蟾宫 悬线法

杂题训练之二

BZOJ_3039_玉蟾宫_(动态规划+悬线法)

悬线法