2013-11-11 09:22:00Morris
[TIOJ][最大矩形(變形)] 1643 - 建築工程規劃
Description
你是一家建築公司的建築工程師,你被派來做一塊空地的建築策劃工作。
這是一塊矩形的空地,你必須在上面選一塊子矩形當作樓房的地基範圍,而為了增加收益,你老闆希望你能夠盡量讓這塊當作地基的子矩形面積越大越好。
但是基於安全上的考量,你不能讓地基覆蓋的區域的最大「土質硬度差」超過 L,意即在地基範圍內的「最大土質硬度」−「最小土質硬度」必須小於等於 L,
否則所建造的房子在突然搖晃時(如發生地震時)將會有倒塌的危險!
你在事前已經得知了這塊空地的土質硬度分布狀況。為了簡化問題,我們把這塊矩形的空地切格成 N×M 的等大正方形區塊,
並假設其中每一個正方型區塊中的土質硬度都是定值 Fij,而你只能選一個子矩形區塊並且所選的子矩形不得包含不完整的正方形區塊。
確立了這些條件後,請問你到底最大可以選取多大的範圍做為地基呢?
Figure 1. 即範例輸入的內容,答案為選標記灰底的子矩形,A = 3×2 = 6。
Input
本題輸入的測試檔只有單筆測試資料,第一行有三個整數 N、M、L。
接下來有 N 行,每一行都有 M 個非負整數代表土質硬度 Fij。
對於所有測試資料,保證1 ≤ N, M ≤ 1000,0 ≤ L ≤ 20,0 ≤ Fij ≤ 109。
Output
一個整數 A 代表至多可以在符合安全的條件之下選取多大矩形面積當作地基的範圍。
Sample Input
3 3 1 1 1 1 1 2 3 2 1 1
Sample Output
6
Source
Skyly & Shik Contest II (Problem D)
先解決子問題,找到 "矩陣中內部元素相同的最大矩形"。
也就是顏色要相同,找到最大矩形。
接著解決大小差值得可能,嘗試每一個區間都染成一色 [x, x+L]
因此染色情況會有 L+1 種,對於每種區間可能做一次查找元素相同的最大矩形辨識答案。
使用單調堆協助找到元素相同的最大矩形,對於不同顏色的話全部 pop 出來。
照理來講是 O(NML) 卻一直 TLE,加入優化輸入後才拿到 AC。
常數可能有點大。
#include <stdio.h>
#include <stack>
#include <algorithm>
using namespace std;
struct Node {
int height, position, color;
Node(int a=0, int b=0, int c=0):
height(a), position(b), color(c) {}
};
int solve(int n, int h[], int c[]) {
int ret = 0;
int i, height, color;
stack<Node> stk;// <height, position, color>
Node e;
h[n] = 0, c[n] = -1;// visual height.
stk.push(Node(-1, 0, 0));
for(i = 0; i <= n; i++) {
height = h[i];
color = c[i];
while(stk.size() > 1 && color != stk.top().color) {
e = stk.top(), stk.pop();
ret = max(ret, (i - e.position) * e.height);
}
e = Node(height, i, color);
while(height < stk.top().height) {
e = stk.top(), stk.pop();
ret = max(ret, (i - e.position) * e.height);
}
if(height > stk.top().height)
stk.push(Node(height, e.position, color));
}
return ret;
}
int n, m, L, h[1005], c[1005];
int g[1005][1005], cg[1005][1005];
int maxRectArea(int n, int m, int g[][1005]) {
int i, j;
int ret = 0, prev[1005] = {};
for(i = 0; i < m; i++) {
for(j = 0; j < n; j++) {
if(i && g[j][i-1] != g[j][i])
prev[j] = 0;
h[j] = ++prev[j], c[j] = g[j][i];
}
ret = max(ret, solve(n, h, c));
}
return ret;
}
int colorProcess(int L) {
int cnt = 0;
int i, j, k;
int ret = 0;
for(i = 0; i <= L; i++) {
for(j = 0; j < n; j++) {
int *p = g[j];
for(k = 0; k < m; k++) {
cg[j][k] = (*p+100-i)/(L+1)*(L+1)+i;
p++;
}
}
ret = max(ret, maxRectArea(n, m, cg));
}
return ret;
}
inline int ReadInt(int *x) {
static char c, neg;
while((c = getchar()) < '-') {if(c == EOF) return EOF;}
neg = (c == '-') ? -1 : 1;
*x = (neg == 1) ? c-'0' : 0;
while((c = getchar()) >= '0')
*x = (*x << 3) + (*x << 1) + c-'0';
*x *= neg;
return 1;
}
int main() {
int i, j;
while(scanf("%d %d %d", &n, &m, &L) == 3) {
for(i = 0; i < n; i++) {
int *p = g[i];
for(j = 0; j < m; j++) {
ReadInt(&p[j]);
}
}
int ret = 0;
ret = colorProcess(L);
printf("%d\n", ret);
}
return 0;
}