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

管理员求大大滴通过。

相关推荐
倒头就睡的小比特3 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼3 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
旖旎夜光4 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark4 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her14 天前
并查集-听课笔记
笔记·算法·并查集
码流子4 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven4 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark4 天前
从算法设计模式看编程思维的抽象能力4
算法
2601_962218614 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法