1 条题解
-
0
题目描述
在18世纪,林清司(Seiji Hayashi)长期担任会津藩日新馆武士学校的教授。为表彰他在教育上的功绩,会津藩主松平容颂(Katanobu Matsudaira)决定赐予他一块位于会津盆地大田野中的矩形庄园。庄园的**宽度和高度**由藩主严格指定,但林教授可以自由选择庄园的位置。
田野中种植了许多日本柿子树(会津特产"无籽柿")。由于林教授特别喜爱柿子,他希望在自己的庄园内尽可能多地包含柿子树。
示例(图1):
- 整个田野是的矩形网格,每个
*
代表一棵柿子树。- 若庄园尺寸为(实线区域),最多包含棵树。
- 若为(虚线区域),最多棵。
- 若为(点线区域),最多棵。
- 注意:庄园的宽度和高度不可交换(与视为不同尺寸)。
输入格式
- 每个测试用例格式如下:
N W H x1 y1 x2 y2 ... xN yN S T
- :柿子树数量()。
- :田野的宽度和高度()。
- :第棵树的坐标(原点为,,,且所有坐标唯一)。
- :庄园的指定宽度和高度(,)。
- 输入以单独一行的结束。
输出格式
对每个测试用例,输出一行:庄园内最多可包含的柿子树数量。
示例
输入:
16 10 8 2 2 2 5 2 7 3 3 3 8 4 2 4 5 4 8 6 4 6 7 7 5 7 8 8 1 8 4 9 6 10 3 4 3 8 6 4 1 2 2 1 2 4 3 4 4 2 5 3 6 1 6 2 3 2 0
输出:
4 3
解题思路
- 网格统计:将柿子树位置标记在的二维数组中。
- 滑动窗口:
- 计算每个可能的矩形区域内树的数目。
- 使用前缀和矩阵优化计算,将时间复杂度从降至。
- 输出最大值:遍历所有可能的矩形位置,统计最大值。
关键公式
- 前缀和矩阵的递推:$$P[i][j] = P[i-1][j] + P[i][j-1] - P[i-1][j-1] + \text{tree}[i][j] $$
- 矩形到的树数目:$$\text{count} = P[i+S-1][j+T-1] - P[i-1][j+T-1] - P[i+S-1][j-1] + P[i-1][j-1] $$
代码实现(C++)
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(NULL); // 将nullptr改为NULL int cnt; while (cin >> cnt && cnt != 0) { int W, H; cin >> W >> H; // 使用二维数组标记柿子树的位置 vector<vector<int> > prefix(W + 1, vector<int>(H + 1, 0)); // 将>>改为> > // 读入柿子树坐标并构建前缀和数组 for (int i = 0; i < cnt; ++i) { int x, y; cin >> x >> y; prefix[x][y] = 1; } // 构建二维前缀和数组 for (int i = 1; i <= W; ++i) { for (int j = 1; j <= H; ++j) { prefix[i][j] += prefix[i - 1][j] + prefix[i][j - 1] - prefix[i - 1][j - 1]; } } int S, T; cin >> S >> T; int max_trees = 0; // 遍历所有可能的矩形 for (int i = 1; i + S - 1 <= W; ++i) { for (int j = 1; j + T - 1 <= H; ++j) { int x2 = i + S - 1; int y2 = j + T - 1; // 利用前缀和数组快速计算矩形内的柿子树数量 int trees = prefix[x2][y2] - prefix[x2][j - 1] - prefix[i - 1][y2] + prefix[i - 1][j - 1]; max_trees = max(max_trees, trees); } } cout << max_trees << '\n'; } return 0; }
复杂度分析
- 时间复杂度:,适用于的约束。
- 空间复杂度:,存储前缀和矩阵。
- 整个田野是的矩形网格,每个
- 1
信息
- ID
- 1030
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者