http://noi.openjudge.cn/ch0405/1793/

好虐的一道题啊。

看数据范围,一眼状压,然后调了好长时间QwQ

很容易想到覆盖的点数作为状态,我用状态i表示至少覆盖状态i表示的点的最小矩形覆盖面积。

又因为矩形一定在两个给出的点上,转移时枚举两个点,用去掉这两个点的状态来更新?

这是错误的做法,反例:4 (0,0) (0,1) (1,0) (1,1)

所以我们需要去掉这两个点的同时,去掉这两个点构成的矩形包含的所有在状态中的点。

但这样还是会WA,因为还需要初始化至少包含一个点(状态中有一个点)的矩形覆盖,只要找和这个点和其他点构成的最小矩形面积就可以了。

这样还要注意,如果计算至少包含两个点的状态(状态中有两个点),最小矩形不一定是这两个点构成的矩形,有可能是这两个点分别和其他点构成的矩形。

所以转移时除了枚举两个点构成的矩形,还要枚举去掉一个点的状态和去掉的这个点的状态来转移,防止状态包含的这些点的最小矩形覆盖没有一个同时覆盖了状态中的两个点。

(如果转移时枚举的两个点的横坐标(或纵坐标)相同,需要分向左向右(或向上向下)两种情况来转移)

提供一组数据(答案为17):

8
2 10
2 7
9 3
2 4
0 7
1 0
3 0
5 5
0

时间复杂度\(O(2^nn^3)\)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int in() {
int k = 0, fh = 1; char c = getchar();
for(; c < '0' || c > '9'; c = getchar())
if (c == '-') fh = -1;
for(; c >= '0' && c <= '9'; c = getchar())
k = k * 10 + c - 48;
return k * fh;
} int sum[20][20], f[40000], n, x[20], y[20], tot, id[20], cnt, a, b, from, h, l, X0, X1, Y0, Y1; int main() {
while (n = in()) {
memset(f, 60, sizeof(f));
f[0] = 0; for(int i = 0; i < n; ++i)
x[i] = in(), y[i] = in();
for(int i = 0; i < n; ++i)
for(int j = i + 1; j < n; ++j) {
if (i == j) sum[i][j] = 0;
h = abs(x[i] - x[j]);
l = abs(y[i] - y[j]);
if (!h) h = 1;
if (!l) l = 1;
sum[i][j] = sum[j][i] = h * l;
}//预处理
for(int i = 0; i < n; ++i) {
tot = (1 << i);
for(int j = 0; j < n; ++j)
if (i != j)
f[tot] = min(f[tot], sum[i][j]);
}//预处理只有一个点 tot = 1 << n; for(int i = 1; i < tot; ++i) {
cnt = 0;
for(int j = 0; j < n; ++j)
if ((1 << j) & i) {
id[++cnt] = j;
f[i] = min(f[i], f[i ^ (1 << j)] + f[1 << j]);//枚举去掉一个点的状态和去掉的这个点的状态,防止状态包含的这些点的最小矩形覆盖没有一个同时覆盖了状态中的两个点
}
for(int j = 1; j < cnt; ++j) {
a = id[j];
for(int k = j + 1; k <= cnt; ++k) {
b = id[k];
from = i;
if (x[a] < x[b]) {X0 = x[a]; X1 = x[b];}
else {X0 = x[b]; X1 = x[a];}
if (y[a] < y[b]) {Y0 = y[a]; Y1 = y[b];}
else {Y0 = y[b]; Y1 = y[a];}
if (X0 == X1) {//分向左向右
++X1;
for(int l = 1; l <= cnt; ++l)
if (X0 <= x[id[l]] && x[id[l]] <= X1 && Y0 <= y[id[l]] && y[id[l]] <= Y1)
from ^= (1 << id[l]);
f[i] = min(f[i], f[from] + sum[a][b]); --X1; --X0;
from = i;
for(int l = 1; l <= cnt; ++l)
if (X0 <= x[id[l]] && x[id[l]] <= X1 && Y0 <= y[id[l]] && y[id[l]] <= Y1)
from ^= (1 << id[l]);
f[i] = min(f[i], f[from] + sum[a][b]);
} else if (Y0 == Y1) {//分向上向下
++Y1;
for(int l = 1; l <= cnt; ++l)
if (X0 <= x[id[l]] && x[id[l]] <= X1 && Y0 <= y[id[l]] && y[id[l]] <= Y1)
from ^= (1 << id[l]);
f[i] = min(f[i], f[from] + sum[a][b]); --Y1; --Y0;
from = i;
for(int l = 1; l <= cnt; ++l)
if (X0 <= x[id[l]] && x[id[l]] <= X1 && Y0 <= y[id[l]] && y[id[l]] <= Y1)
from ^= (1 << id[l]);
f[i] = min(f[i], f[from] + sum[a][b]);
} else {
for(int l = 1; l <= cnt; ++l)
if (X0 <= x[id[l]] && x[id[l]] <= X1 && Y0 <= y[id[l]] && y[id[l]] <= Y1)
from ^= (1 << id[l]);
f[i] = min(f[i], f[from] + sum[a][b]);
}
}
}
} printf("%d\n", f[tot - 1]);
}
return 0;
}

一年前WA的题现在才A。。。

【OpenJudge 1793】矩形覆盖的更多相关文章

  1. NOIP2002矩形覆盖[几何DFS]

    题目描述 在平面上有 n 个点(n <= 50),每个点用一对整数坐标表示.例如:当 n=4 时,4个点的坐标分另为:p1(1,1),p2(2,2),p3(3,6),P4(0,7),见图一. 这 ...

  2. bzoj 1185 旋转卡壳 最小矩形覆盖

    题目大意 就是求一个最小矩形覆盖,逆时针输出其上面的点 这里可以看出,那个最小的矩形覆盖必然有一条边经过其中凸包上的两个点,另外三条边必然至少经过其中一个点,而这样的每一个点逆时针走一遍都满足单调性 ...

  3. [剑指OFFER] 斐波那契数列- 跳台阶 变态跳台阶 矩形覆盖

    跳台阶 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法. class Solution { public: int jumpFloor(int number) ...

  4. NOIP2002 矩形覆盖

    题四 矩形覆盖(存盘名NOIPG4) [问题描述]: 在平面上有 n 个点(n <= 50),每个点用一对整数坐标表示.例如:当 n=4 时,4个点的坐标分另为:p1(1,1),p2(2,2), ...

  5. UVA-11983-Weird Advertisement(线段树+扫描线)[求矩形覆盖K次以上的面积]

    题意: 求矩形覆盖K次以上的面积 分析: k很小,可以开K颗线段树,用sum[rt][i]来保存覆盖i次的区间和,K次以上全算K次 // File Name: 11983.cpp // Author: ...

  6. 【旋转卡壳+凸包】BZOJ1185:[HNOI2007]最小矩形覆盖

    1185: [HNOI2007]最小矩形覆盖 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 1945  Solve ...

  7. BZOJ:1185: [HNOI2007]最小矩形覆盖

    1185: [HNOI2007]最小矩形覆盖 这计算几何……果然很烦…… 发现自己不会旋转卡壳,补了下,然后发现求凸包也不会…… 凸包:找一个最左下的点,其他点按照与它连边的夹角排序,然后维护一个栈用 ...

  8. BZOJ 1185: [HNOI2007]最小矩形覆盖 [旋转卡壳]

    1185: [HNOI2007]最小矩形覆盖 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 1435  Solve ...

  9. 矩形覆盖(JAVA)

    矩形覆盖 题目描述 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形.请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 思路:最初看到这题,只能通过画图归纳来寻找规律. ...

随机推荐

  1. 解决 安装cocoapods失败,提示 requires Ruby version >=2.2.2

    步骤如下: rvm install ruby-2.2 但是,但是竟然报错了,具体我忘记额,但是是权限和brew的问题,那么我又转向修复brew: // 清理原来brew rm -rf /usr/loc ...

  2. 适配ios10(iTunes找不到构建版本)

    前两天上架App遇到一个比较神奇的问题,打包好的项目使用Application Loader上传成功,但是在iTunes里面却找不到构建版本,App的活动页面也没有相应的版本. 之前了解IOS10对用 ...

  3. 基于Ruby的Watir-WebDriver自动化测试方案

    Watir-WebDriver       —— 软件测试的自动化时代 QQ群:160409929 自动化测试方案书 系统架构 该自动化测试框架分三个模块:Test用例.Control控制层.Tool ...

  4. RubyMine不能调试Rails项目的问题

    需要安装debase gem,而且在项目的GemFile中禁用byebug

  5. OkHttp简介

    什么是OKHttp 一般在Java平台上,我们会使用Apache HttpClient作为Http客户端,用于发送 HTTP 请求,并对响应进行处理.比如可以使用http客户端与第三方服务(如SSO服 ...

  6. Linux 日志报错 xxx blocked for more than 120 seconds

    监控作业发现一台服务器(Red Hat Enterprise Linux Server release 5.7)从凌晨1:32开始,有一小段时间无法响应,数据库也连接不上,后面又正常了.早上检查了监听 ...

  7. PHP命名规范

    以下文字全部摘自<PHP从入门到精通>这本书,谨以此作为标准. 就一般约定而言,类.函数和变量的名字应该是能够让代码阅读者能够容易地知道这些代码的作用,应该避免使用凌磨两可的命名. 1. ...

  8. window.frameElement的使用

    window.frameElement的使用: 返回嵌入当前window对象的元素(比如 <iframe> 或者 <object>),如果当前window对象已经是顶层窗口,则 ...

  9. MySQL Nested-Loop Join算法学习

    不知不觉的玩了两年多的MySQL,发现很多人都说MySQL对比Oracle来说,优化器做的比较差,其实某种程度上来说确实是这样,但是毕竟MySQL才到5.7版本,Oracle都已经发展到12c了,今天 ...

  10. java实现批量下载百度图片搜索到的图片

    就是写的个小程序,用于记录一下,方便后续查看,首先感谢下面这个博客,从这篇文章衍生的吧,大家可以学习下: http://www.cnblogs.com/lichenwei/p/4610298.html ...