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. Android—Socket中关闭IO流后导致Socket关闭不能再收发数据的解决办法

    以Socket发送数据为例: 发送数据时候要声明:DataOutputStream os = new DataOutputStream(socket.getOutputStream()); 最近开发遇 ...

  2. Android开发学习——SQLite数据库与单元测试

    SQLite数据库 轻量级关系型数据库 创建数据库需要使用的api:SQLiteOpenHelper  public class Myopenhelper extends SQLiteOpenHelp ...

  3. ListView控件

      打气筒工具:将R.layout.item_listview布局添加到相应的view控件里面 View view=LayoutInflater.from(ScondPro.this).inflate ...

  4. 【原】iOS动态性(三) Method Swizzling以及AOP编程:在运行时进行代码注入

    概述 今天我们主要讨论iOS runtime中的一种黑色技术,称为Method Swizzling.字面上理解Method Swizzling可能比较晦涩难懂,毕竟不是中文,不过你可以理解为“移花接木 ...

  5. sizeof与strlen的区别

    1 sizeof是操作符,而strlen是库函数: 2 sizeof的参数可以为任意变量或类型,而strlen必须以char*做参数,且字符串必须以‘/0’结尾: 3 数组名用作sizeof参数时不会 ...

  6. JVM-漫游

    Write once, Run Any where. Java Virtual Machine – JVM 的存在让 Java 开发变得简单,并且一次编写多处运行.其实,JVM 就是一个抽象的计算机, ...

  7. SSRS 2008 ReportServerTempDB增长异常分析

    这两天收到一SQL 2008 R2数据库服务器的磁盘空间告警,在检查过程中发现ReportServerTempDB已经暴增到60多GB,其中数据文件接近60G,日志文件9G大小左右.如下截图所示 我们 ...

  8. [AlwaysOn Availability Groups]排查:AG超过RPO

    排查:AG超过RPO 在异步提交的secondary上执行了切换,你可能会发现数据的丢失大于RPO,或者在计算可以忍受的数据都是超过了RPO. 1.通常原因 1.网络延迟太高,网络吞吐量太低,导致Pr ...

  9. JDBC API Description

    package java.sql description What the JDBCTM 4.2 API Includes Versions What the java.sql Package Con ...

  10. 关于datetime 和 int 之间相互转换

    在其他地方看到一个有点意思的东西.是记录转换规则的. DECLARE @Date1 DATETIME = '2016-06-21 11:53:00' , @Date2 DATETIME = '2016 ...