最近更新事情
最近学业较重,更新较慢,抱歉。
P1034 NOIP 2002 提高组 矩形覆盖
题目描述
在平面上有 nnn 个点,每个点用一对整数坐标表示。例如:当 n=4n=4n=4 时,444 个点的坐标分别为:p1(1,1)p_1(1,1)p1(1,1),p2(2,2)p_2(2,2)p2(2,2),p3(3,6)p_3(3,6)p3(3,6),p4(0,7)p_4(0,7)p4(0,7),见图一。

这些点可以用 kkk 个矩形全部覆盖,矩形的边平行于坐标轴。当 k=2k=2k=2 时,可用如图二的两个矩形 s1,s2s_1,s_2s1,s2 覆盖,s1,s2s_1,s_2s1,s2 面积和为 444。问题是当 nnn 个点坐标和 kkk 给出后,怎样才能使得覆盖所有点的 kkk 个矩形的面积之和为最小呢?
约定:覆盖一个点的矩形面积为 000;覆盖平行于坐标轴直线上点的矩形面积也为 000。各个矩形必须完全分开(边线与顶点也都不能重合)。
输入格式
第一行共两个整数 n,kn,kn,k,含义如题面所示。
接下来 nnn 行,其中第 i+1i+1i+1 行有两个整数 xi,yix_i,y_ixi,yi,表示平面上第 iii 个点的坐标。
输出格式
共一行一个整数,为满足条件的最小的矩形面积之和。
输入输出样例 #1
输入 #1
4 2
1 1
2 2
3 6
0 7
输出 #1
4
说明/提示
对于 100%100\%100% 数据,满足 1≤n≤501\le n \le 501≤n≤50,1≤k≤41 \le k \le 41≤k≤4,0≤xi,yi≤5000 \le x_i,y_i \le 5000≤xi,yi≤500。
【题目来源】
NOIP 2002 提高组第四题
思路
我认为这是道递归题,要剪枝和回溯,以防超时,但似乎好像数据量太小,不用了。
80分
我们可以考虑考虑用 DFS 进行搜索了,如果是所有点都被覆盖的话,可以让一个一个点加入此矩形,然后需要维护 x1x_1x1 和 x2x_2x2 和 y1y_1y1 和 y2y_2y2,加入点,我们需要更新这个边界,算增加了多少。
做到这,我们找找重叠的就行了。
AC
我就高高兴兴提交了,结果 808080 分,想了一顿子,想明白要加重叠判断,加了就对了。
cpp
bool pd(int p, int q) {
if (a[p] == 0x7fffffff || a[q] == 0x7fffffff) return true;
if (b[p] < a[q]) return true;
if (a[p] > b[q]) return true;
if (d[p] < c[q]) return true;
if (c[p] > d[q]) return true;
return false;
}
bool pd2() {
for (int i = 1; i <= k; i++) {
for (int j = i + 1; j <= k; j++) {
if (!pd(i, j)) return false;
}
}
return true;
}
所以警示后人。
代码
cpp
#include<bits/stdc++.h>
using namespace std;
int n,k,x[55], y[55],ans = 0x7fffffff,a[5], b[5], c[5], d[5];
int chuli(int id) {
if (a[id] == 0x7fffffff) return 0;
return (b[id] - a[id]) * (d[id] - c[id]);
}
bool pd(int p, int q) {
if (a[p] == 0x7fffffff || a[q] == 0x7fffffff) return true;
if (b[p] < a[q]) return true;
if (a[p] > b[q]) return true;
if (d[p] < c[q]) return true;
if (c[p] > d[q]) return true;
return false;
}
bool pd2() {
for (int i = 1; i <= k; i++) {
for (int j = i + 1; j <= k; j++) {
if (!pd(i, j)) return false;
}
}
return true;
}
void dfs(int u, int sum) {
if (sum >= ans) return;
if (!pd2()) return;
if (u == n) {
ans = sum;
return;
}
for (int i = 1; i <= k; i++) {
int x1 = a[i],x2 = b[i],y1 = c[i],y2 = d[i],o = chuli(i);
a[i] = min(a[i], x[u]);
b[i] = max(b[i], x[u]);
c[i] = min(c[i], y[u]);
d[i] = max(d[i], y[u]);
int now = chuli(i);
dfs(u + 1, sum - o + now);
a[i] = x1;b[i] = x2;c[i] = y1;d[i] = y2;
}
}
int main() {
cin >> n >> k;
for (int i = 0; i < n; i++) cin >> x[i] >> y[i];
for (int i = 1; i <= k; i++) {
a[i] = 0x7fffffff;b[i] = -0x7fffffff;c[i] = 0x7fffffff;d[i] = -0x7fffffff;
}
dfs(0, 0);
cout << ans << endl;
return 0;
}
后记
算过了,复杂度在 O(kn×k2)O(k^n \times k^2)O(kn×k2)。
管理员求大大滴通过。