问题描述:
Jaguar国王在一场战役大胜后决定建造一个金字塔,一方面作为纪念战争胜利的纪念碑,同时亦用作埋葬在战斗中阵亡将士们的墓地。该金字塔将建在战场的所在地,有一个a列b行的矩形底部。在金字塔的底层内将有一个较小的c列d行的矩形墓室,用来存放阵亡将士们的遗体以及他们所用过的武器。
国王的建筑师将该战场分为m列n行小方格的网格。每个小方格的高度用一个整数表示。
金字塔及其内部的墓室均应覆盖网格的完整的小方格,而且其边必须与战场的边平行。金字塔内墓室小方格的高度必须保持原有的高度不变,但金字塔底部的其余地面则需要平整,平整的方法是将高度较高的小方格内的砂土移到较低的小方格内,这样一来,金字塔底部的最后高度将是底部所覆盖的所有小方格(墓室小方格除外)高度的平均值。建筑师有权选择墓室在金字塔内的位置,但墓室四周要有至少一小方格厚度的墙围绕。
建筑师希望在战场上找到一块最佳的位置来建造该金字塔及其内部的墓室,使得对于给定大小的金字塔,其底部的高度尽可能高。
图中所示是一个战场的例子,每个小方格内的整数表示该格所处区域内的高度。灰色部份表示金字塔的底部,灰色部份所包围的白色部份则表示墓室的位置。该图给出了一个最佳位置。
任务
对于给定尺寸的战场、金字塔和墓室大小以及战场上所有小方格的高度,请编写一程序找出建造金字塔及其墓室的最佳位置,使得金字塔底部的高度为最高。
限制条件
3≤m≤1000
3≤n≤1000
3≤a≤m
3≤b≤ n
1≤c≤a–2
1≤d≤b–2
所有的高度都是1-100之间的整数。
输入:
你的程序必须从文件pyramid.in中读入所需数据,其格式如下:
pyramid.in
8 5 5 3 2 1 1 5 10 3 7 1 2 5 6 12 4 4 3 3 1 5 2 4 3 1 6 6 19 8 1 1 1 3 4 2 4 5 6 6 3 3 3 2 2 2
第1行:共有6个以空格分开的正整数,它们顺次分别为:m,n,a,b, c, and d.
随后n行:每行有m个空格分开的整数,每行表示一横行小方格的高度。其中第一行表示战场小方格最上面的一行(第一行),而最后一行表示最下面的一行(第n行)。每行的m个整数依次表示该行上从第一列开始的小方格的高度。
输出:
你的程序必须将结果数据输出到pyramid.out的文件中。
pyramid.out
4 1 6 2
第1行:必须输出两个由空格分开的整数,它们表示它们表示金字塔的底部的左上角位置,其中第一个整数代表列的坐标,而第二个整数则代表行的坐标,
随后n行: 必须输出两个由空格分开的整数,它们表示金字塔内部的墓室的左上角位置,其中第一个整数代表列的坐标,而第二个整数则代表行的坐标。
注意:
如果存在多个最优位置,那么你输出其中一个均被视为正确。
评分:
对部分总值为30分的测试数据而言,这些测试将满足以下条件:
3≤m≤10
3≤n≤10
分析
这又是一道之前连续一系列的跟区间前缀和相关的题目。要求最大的矩形内和,那么少不了先预处理前缀和。用数组cd和数组ab来存储以某个点为右下角的c*d或a*b的矩阵的数字和。
然后我们计算在一个a*b矩阵大小范围内,所有符合条件的c*d的矩阵的数字和的最小值(这里用到了两次单调队列),然后暴力枚举所有a*b的矩阵。
卡点
这道题目由于来自于遥远的埃及,题目当中有一些小细节,与我们平时的做法有些不同。例如,这道题当中先读列再读行。所以中间到底是行还是列,要分清楚(非常神奇)。
由于这道题我们用了单调队列来求最小值,所以记录坐标有些麻烦。那么我们不放用一些小技巧。我们暴力枚举a*b的矩阵以后,在这个a*b的矩阵范围内寻找一个c*d的矩阵它的和符合a*b的矩阵里的最小值,也就是我们得出最小值以后倒过来推坐标。而且这样并不会超时。
柴老师提出原来程序当中的goto使用不是很妥当,破坏了程序的逻辑性和美感,尽量不要使用。注释掉了。
程序
1 #include2 #include 3 #include 4 #include 5 #include 6 using namespace std; 7 inline int read() { 8 int res = 0; bool bo = 0; char c; 9 while (((c = getchar()) < '0' || c > '9') && c != '-'); 10 if (c == '-') bo = 1; else res = c - 48; 11 while ((c = getchar()) >= '0' && c <= '9') 12 res = (res << 3) + (res << 1) + (c - 48); 13 return bo ? ~res + 1 : res; 14 } 15 const int N = 1005; 16 int m, n, A, B, C, D, sum[N][N], ab[N][N], cd[N][N], H, T, que[N], id[N], px[N][N], py[N][N], res = 0; 17 int resi, resj, resk, resl; 18 int main() 19 { 20 freopen("pyramid.in","r",stdin); 21 freopen("pyramid.out","w",stdout); 22 n = read(); m = read(); B = read(); A = read(); D = read(); C = read(); 23 for (int i = 1; i <= m; i++) 24 for (int j = 1; j <= n; j++) 25 sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + read(); 26 for (int i = A; i <= m; i++) 27 for (int j = B; j <= n; j++) 28 ab[i][j] = sum[i][j] - sum[i - A][j] - sum[i][j - B] + sum[i - A][j - B]; 29 for (int i = C; i <= m; i++) 30 for (int j = D; j <= n; j++) 31 cd[i][j] = sum[i][j] - sum[i - C][j] - sum[i][j - D] + sum[i - C][j - D]; 32 for (int i = C; i <= m; i++) 33 { 34 H = T = 0; 35 for (int j = D; j <= B - 2; j++) 36 { 37 while (H < T && que[T] > cd[i][j]) 38 T--; 39 que[++T] = cd[i][j]; 40 id[T] = j; 41 } 42 px[i][B - 2] = que[H + 1]; 43 for (int j = D + 1; j - D + B - 2 <= n; j++) 44 { 45 while (H < T && que[T] > cd[i][j - D + B - 2]) 46 T--; 47 que[++T] = cd[i][j - D + B - 2]; 48 id[T] = j - D + B - 2; 49 if (id[H + 1] == j - 1) 50 H++; 51 px[i][j - D + B - 2] = que[H + 1]; 52 } 53 } 54 for (int j = B - 2; j <= n; j++) 55 { 56 H = T = 0; 57 for (int i = C; i < A; i++) 58 { 59 while (H < T && que[T] > px[i][j]) 60 T--; 61 que[++T] = px[i][j]; 62 id[T] = i; 63 } 64 py[A - 2][j] = que[H + 1]; 65 for (int i = C + 1; i - C + A - 2 <= m; i++) 66 { 67 while (H < T && que[T] > px[i - C + A - 2][j]) 68 T--; 69 que[++T] = px[i - C + A - 2][j]; 70 id[T] = i - C + A - 2; 71 if (id[H + 1] == i - 1) 72 H++; 73 py[i - C + A - 2][j] = que[H + 1]; 74 } 75 } 76 for (int i = A; i <= m; i++) 77 for (int j = B; j <= n; j++) 78 { 79 if (ab[i][j] - py[i-1][j-1] > res) 80 { 81 res = ab[i][j] - py[i - 1][j - 1]; 82 for (int k = i - A + C + 1; k <= i - 1; k++) 83 for (int l = j - B + D + 1; l <= j - 1; l++) 84 if (cd[k][l] == py[i-1][j-1]) 85 { 86 resk = k, resl = l; 87 // goto lnk; 88 } 89 // lnk: 90 resi = i; 91 resj = j; 92 } 93 } 94 cout << resj-B+1 << " " << resi-A+1 << endl; 95 cout << resl-D+1 << " " << resk-C+1 << endl; 96 return 0; 97 }