题解:Luogu P1034 [NOIP 2002 提高组] 矩形覆盖
首先看到本题的数据范围:$ 1 \leq n \leq 50, 1\leq k \leq 4$,数量非常少。
如果暴力将每个点加入几个不同的集合中,即使对于 \(n \leq 50\) 这种极小的数据也是指数级的(当 \(k \leq 4,n=50\) 时,最坏复杂度达到了 \(4^{50}\),无法通过)。
于是我们考虑使用搜索进行操作。
条件:
- 矩形边必须平行于坐标轴;
- 各矩形必须完全分开(边线和顶点都不能重合);
- 覆盖单个点或共线点的矩形面积为 \(0\)。
1. 状态表示
- 用四元组表示矩形:\((x_1, y_1, x_2, y_2, c)\);
- \((x_1,y_1)\) 为左下角,\((x_2,y_2)\) 为右上角,\(c\) 为包含点数。
2. DFS 框架
void dfs(int u) { // 处理第 u 个点
if (u == n + 1) {
计算所有矩形面积和,更新最优答案;
return;
}
for (int i = 0; i < k; i++) { // 尝试加入第 i 个矩形
保存第 i 个矩形的当前状态;
将第 u 个点加入第 i 个矩形;
更新矩形边界;
if (检查所有矩形互不相交) {
dfs(u + 1); // 继续处理下一个点
}
恢复第 i 个矩形状态; // 回溯
}
}
加入点操作:
if (矩形为空) {
x1 = x2 = 点的 x 坐标;
y1 = y2 = 点的 y 坐标;
c = 1;
} else {
x1 = min(x1, 点的 x 坐标);
y1 = min(y1, 点的 y 坐标);
x2 = max(x2, 点的 x 坐标);
y2 = max(y2, 点的 y 坐标);
c++;
}
相交判断:
两矩形 A,B 不相交当且仅当满足以下条件之一:
- A 在 B 的左边:\(A_{x_2} < B_{x_1}\);
- A 在 B 的右边:\(A_{x_1} > B_{x_2}\);
- A 在 B 的下边:\(A_{y_2} < B_{y_1}\);
- A 在 B 的上边:\(A_{y_1} > B_{y_2}\)。
bool flag = (A.x2 < B.x1) || (B.x2 < A.x1) ||
(A.y2 < B.y1) || (B.y2 < A.y1);
面积计算:
int calc(int i) {
if (r[i].c <= 1) return 0; // 单点或空矩形
return (r[i].x2 - r[i].x1) * (r[i].y2 - r[i].y1);
}
最后是你们最爱的完整答案:
#include <bits/stdc++.h>
#define N 55
#define INF 0x3f3f3f3f
using namespace std;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
inline void write(int x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
inline void writeln(int x) {
write(x);
putchar('\n');
}
struct point {
int x, y;
} p[N];
struct node {
int x1, y1, x2, y2;
int c;
} r[5];
int n, k, ans;
int calc(int i) {
if (r[i].c <= 1) return 0;
return (r[i].x2 - r[i].x1) * (r[i].y2 - r[i].y1);
}
bool chk() {
for (int i = 0; i < k; i++) {
for (int j = i + 1; j < k; j++) {
if (r[i].c > 0 && r[j].c > 0) {
if (!(r[i].x2 < r[j].x1 || r[j].x2 < r[i].x1 ||
r[i].y2 < r[j].y1 || r[j].y2 < r[i].y1)) {
return false;
}
}
}
}
return true;
}
void dfs(int u) {
if (u == n + 1) {
int s = 0;
for (int i = 0; i < k; i++) {
s += calc(i);
}
ans = min(ans, s);
return;
}
for (int i = 0; i < k; i++) {
node t = r[i];
if (r[i].c == 0) {
r[i].x1 = r[i].x2 = p[u].x;
r[i].y1 = r[i].y2 = p[u].y;
r[i].c = 1;
} else {
r[i].x1 = min(r[i].x1, p[u].x);
r[i].y1 = min(r[i].y1, p[u].y);
r[i].x2 = max(r[i].x2, p[u].x);
r[i].y2 = max(r[i].y2, p[u].y);
r[i].c++;
}
if (chk()) {
dfs(u + 1);
}
r[i] = t;
}
}
int main() {
n = read();
k = read();
for (int i = 1; i <= n; i++) {
p[i].x = read();
p[i].y = read();
}
ans = INF;
dfs(1);
writeln(ans);
return 0;
}