P1034 [NOIP 2002 提高组] 矩形覆盖题解

最近更新事情

最近学业较重,更新较慢,抱歉。

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)。

管理员求大大滴通过。

相关推荐
明月_清风1 小时前
从二叉树到 B+ 树:一文搞懂工程中「树」的演化之道
数据结构·算法·go
渡我白衣1 小时前
并查集:基础认识与模拟实现
android·java·javascript·数据结构·c++·算法·并查集
hetao17338371 小时前
2026-09-01~09-04 hetao1733837 的刷题记录
c++·算法
Evand J2 小时前
【MATLAB例程,图像滤波5】 反谐波均值滑动窗口滤波(CHMF)图像降噪与质量评价,附代码下载链接
图像处理·算法·计算机视觉·matlab·均值算法·滑动窗口滤波·均值滑动
血小板要健康2 小时前
链表 阶段算法总结
java·数据结构·笔记·算法·leetcode·链表
a187927218312 小时前
【算法】回溯算法(三):三记重锤与 N 皇后——记忆化、状态设计与三层漏斗
算法·leetcode·go·剪枝·回溯·n皇后·算法讲解
HugoStudio_SWAN4 小时前
洛谷 P1420 / P1179 / B4262 最长连号、数字统计与词频统计——统计的三种面孔
c++·学习·程序人生·算法
青 春 记 忆5 小时前
LeetCode 350. 两个数组的交集 II|Python 解法详解
python·算法·leetcode
阳明山水6 小时前
销量预测2025—2026:从模型竞赛到系统融合的范式转型
人工智能·深度学习·算法·机器学习·架构
桐盛科技6 小时前
拒绝“漂绿”风险:基于边缘计算的碳排放数据清洗算法与实时校验逻辑
人工智能·算法·边缘计算