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

管理员求大大滴通过。

相关推荐
仍然.8 分钟前
算法题目---BFS解决最短路问题
算法·宽度优先
渡众机器人10 分钟前
第八届全球校园人工智能算法精英大赛-算法应用赛-空地协同侦排挑战赛规则
人工智能·算法
wayz1121 分钟前
Overlap:HWMA(Holt-Winter移动平均线)技术指标详解
算法·金融·数据分析·量化交易·特征工程
Shadow(⊙o⊙)39 分钟前
专题四:前缀和
数据结构·算法
JAVA面经实录9171 小时前
高频算法面试题
java·计算机网络·算法·面试
qq_452396231 小时前
第十一篇:《资源管理:Requests/Limits、ResourceQuota、LimitRange》
算法·贪心算法
Tisfy1 小时前
LeetCode 2095.删除链表的中间节点:两次遍历 / 一次遍历(快慢指针)
算法·leetcode·链表·题解·双指针
Irissgwe1 小时前
AVL树详解
数据结构·c++·算法·二叉树·c·二叉搜索树·avl
凌波粒1 小时前
LeetCode--131.分割回文串(回溯算法)
算法·leetcode·职场和发展
北域码匠1 小时前
奇偶归并排序:并行计算的排序利器
数据结构·算法·c#·排序算法