Description

The CE digital company has built an Automatic Painting Machine (APM) to paint a flat board fully covered by adjacent non-overlapping rectangles of different sizes each with a predefined color. 

To color the board, the APM has access to a set of brushes. Each brush has a distinct color C. The APM picks one brush with color C and paints all possible rectangles having predefined color C with the following restrictions: 
To avoid leaking the paints and mixing colors, a rectangle can only be painted if all rectangles immediately above it have already been painted. For example rectangle labeled F in Figure 1 is painted only after rectangles C and D are painted. Note that each rectangle must be painted at once, i.e. partial painting of one rectangle is not allowed. 
You are to write a program for APM to paint a given board so that the number of brush pick-ups is minimum. Notice that if one brush is picked up more than once, all pick-ups are counted. 

Input

The first line of the input file contains an integer M which is the number of test cases to solve (1 <= M <= 10). For each test case, the first line contains an integer N, the number of rectangles, followed by N lines describing the rectangles. Each rectangle R is specified by 5 integers in one line: the y and x coordinates of the upper left corner of R, the y and x coordinates of the lower right corner of R, followed by the color-code of R. 
Note that: 
  1. Color-code is an integer in the range of 1 .. 20.
  2. Upper left corner of the board coordinates is always (0,0).
  3. Coordinates are in the range of 0 .. 99.
  4. N is in the range of 1..15.

Output

One line for each test case showing the minimum number of brush pick-ups.

Sample Input

1
7
0 0 2 2 1
0 2 1 6 2
2 0 4 2 1
1 2 4 4 2
1 4 3 6 1
4 0 6 4 1
3 4 6 6 2

Sample Output

3

思路:

1. 拓扑排序加深搜

2. 拓扑排序加广搜

3. 状态压缩DP. 设 dp[s][i] 表示当前状态为 s 时, 刚画完第 i 个矩形所用的最少画笔数. s = [1, 1<<15), s 的二进制表示中, 第 i 位 为1 表示第 i 个矩形已经被涂完色.

dp[news][i] = min(dp[news][i], dp[olds][j]+1)        if color[i] != color[j]

= min(dp[olds][j])                               if color[i] == color[j]

其中, news = (olds | 1<<i)

上述状态转移方程的意思是, 要计算 dp[s][i] 的值, 那么考虑当前所有 dp[olds][j], 其中 s = (olds|1<<i), 假如 j 的颜色和 i 的颜色相同, 这不需要另拿画笔, 否则, 画笔数加 1

当然, 对 i 进行涂色需要满足 i 的直接前驱都已被涂完

总结:

1. 这道题近似于暴力破解, 枚举所有状态集合的所有状态, 在某个状态 s 下, 以 s 中以涂色的某个矩形为支点来更新一个还未被涂色的点

2. 第 48 行代码错过一次, 把 i 写成了 j

3. 第 45 行很精髓, 我本打算用一个 for 循环进行判断的

4. 第 44, 48 行, 体现了 (1) 的思想, 即以 k 为支点来更新 i

代码:

#include <iostream>
using namespace std; class tangle {
public:
int x1, y1, x2, y2;
int color;
tangle(int _x1, int _y1, int _x2, int _y2):x1(_x1), y1(_y1), x2(_x2), y2(_y2) {}
tangle() {
tangle(0, 0, 0, 0);
}
};
const int INF = 0X3F3F3F3F;
int M, N;
tangle tangles[20];
int dp[1<<15][20];
int up[20]; bool isUpper(int i, int j) {
if(tangles[i].x2 != tangles[j].x1) return false;
if(tangles[i].y1 >= tangles[j].y2) return false;
if(tangles[i].y2 <= tangles[j].y1) return false;
return true;
}
void pre_process() {
memset(up, 0, sizeof(up));
for(int i = 1; i <= N; i ++) {
for(int j = 1; j <= N; j ++) {
if(isUpper(i, j))
up[j] = (up[j]|(1<<(i-1)));
}
} memset(dp, 0x3f, sizeof(dp));
for(int i = 1; i <= N; i ++)
if(up[i] == 0)
dp[1<<(i-1)][i] = 1; }
int mainFunc() {
int END = (1<<N) -1;
for(int s = 1; s <= END; s ++) { // 从状态 s 导出 dp[s][i], 当前 s 第 i 个矩形不能被涂色
for(int i = 1; i <= N; i ++) { // 将要给第 i 个矩形涂色
if(s&(1<<(i-1)) ) continue; // 状态 s 中, 对应第 i 个矩形已经被涂完了
if((s&up[i]) != up[i]) continue; // 确保 i 的直接前驱都已涂完颜色
for(int k = 1; k <= N; k ++) {
if(!(s&(1<<(k-1)))) continue;
int news = (s|1<<(i-1)); // update 新的 dp[][]
if(tangles[i].color != tangles[k].color)
dp[news][i] = min(dp[news][i], dp[s][k]+1);
else
dp[news][i] = min(dp[news][i], dp[s][k]);
}
}
}
int ans = INF;
for(int i = 1; i <= N; i ++) {
ans = min(ans, dp[END][i]);
}
return ans;
}
int main() {
freopen("E:\\Copy\\ACM\\poj\\1691\\in.txt", "r", stdin);
cin >> M;
while( M -- >= 1) {
cin >> N;
for(int i = 1; i <= N; i ++) {
scanf("%d%d%d%d%d", &tangles[i].x1, &tangles[i].y1, &tangles[i].x2, &tangles[i].y2, &tangles[i].color);
}
pre_process();
cout << mainFunc() << endl;
}
return 0;
}

  

POJ 1691 Painting a Board(状态压缩DP)的更多相关文章

  1. poj 3311 floyd+dfs或状态压缩dp 两种方法

    Hie with the Pie Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 6436   Accepted: 3470 ...

  2. POJ 2686_Traveling by Stagecoach【状态压缩DP】

    题意: 一共有m个城市,城市之间有双向路连接,一个人有n张马车票,一张马车票只能走一条路,走一条路的时间为这条路的长度除以使用的马车票上规定的马车数,问这个人从a出发到b最少使用时间. 分析: 状态压 ...

  3. poj 2411 Mondriaan's Dream_状态压缩dp

    题意:给我们1*2的骨牌,问我们一个n*m的棋盘有多少种放满的方案. 思路: 状态压缩不懂看,http://blog.csdn.net/neng18/article/details/18425765 ...

  4. poj 1185 炮兵阵地 [经典状态压缩DP]

    题意:略. 思路:由于每个大炮射程为2,所以如果对每一行状态压缩的话,能对它造成影响的就是上面的两行. 这里用dp[row][state1][state2]表示第row行状态为state2,第row- ...

  5. POJ 1038 Bug Integrated Inc(状态压缩DP)

    Description Bugs Integrated, Inc. is a major manufacturer of advanced memory chips. They are launchi ...

  6. poj 2411 Mondriaan's Dream(状态压缩dP)

    题目:http://poj.org/problem?id=2411 Input The input contains several test cases. Each test case is mad ...

  7. poj 2686 Traveling by Stagecoach ---状态压缩DP

    题意:给出一个简单带权无向图和起止点,以及若干张马车车票,每张车票可以雇到相应数量的马. 点 u, v 间有边时,从 u 到 v 或从 v 到 u 必须用且仅用一张车票,花费的时间为 w(u, v) ...

  8. POJ 1185 炮兵阵地(状态压缩DP)

    题解:nState为状态数,state数组为可能的状态 代码: #include <map> #include <set> #include <list> #inc ...

  9. POJ 3254 Corn Fields(状态压缩DP)

    题目大意:给出一个M*N的矩阵,元素为0表示这个地方不能种玉米,为1表示这个地方能种玉米,现在规定所种的玉米不能相邻,即每行或者没列不能有相邻的玉米,问一共有多少种种植方法. 举个例子: 2 3 1 ...

随机推荐

  1. Windows10 64位 Python2.7 Matplotlib安装

    为了安装Matplotlib 百度了一大堆,也下载了一大堆安装包,结果还是报错ImportError: DLL load failed: %1 不是有效的 Win32 应用程序. 后来直接从官网看怎么 ...

  2. jquery ajax异步提交表单数据的方法

    使用jquery的ajax方法可以异步提交表单,成功后后台返回json数据,回调函数处理,可以不用刷新页面,达到异步的目的: 处理表单的数据可以用serialize()方法进行序列化,而如果提交的数据 ...

  3. 纯css3实现的3D按钮

    前面已经为大家介绍了好多纯css3实现的按钮.今天要再给大家带来一款纯css3实现的3D按钮.在实例中给出了五种颜色的3D按钮.效果图如下: 在线预览   源码下载 实现的代码. html代码: &l ...

  4. mysql的OFFSET实现分页

    使用limit 可以实现分页比如 limit 0,5  是从1到5条, limit 5,5  是从,6到10条, 使用limit offset 时 limit 5 offset 0 从 1 到5 条 ...

  5. 【Unity】UGUI的Text各种小问题

    Text:用中文输入法时,无法输入汉字.输入了拼音后,按回车键无反应.目前的办法是在别的地方打好字后复制过来. Font:字体必须选一个,选None则文字变成一串黑色方块. Font Size:文字大 ...

  6. pthread_self()究竟根据什么来得到线程的标识符????

    #include<stdlib.h> #include<pthread.h> #include<stdio.h> #include<sched.h> # ...

  7. 线程安全的atomic wrapper classes例子

    先参考一个例子 http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html#!comments 即使只是i++,实际上也是由多个原子 ...

  8. 简单文件系统构建ramdisk

    1.  BusyBox编译工具,包含bin, sbin, usr,  linuxrc. 2.  添加相关重要目录:dev,  etc,  mnt, proc,  sys, lib, var, tmp. ...

  9. VMWare虚拟机安装创建虚拟机的使用教程

    VMWare虚拟机安装创建虚拟机的使用教程   在配置虚拟机之前需要安装它,VMWare软件的安装过程比较简单,在安装在之前应该先看下说明文档.下面以VMWare Workstation6.5虚拟机 ...

  10. C++实现八皇后问题

    C++实现八皇后问题 #include <iostream> using std::cout; using std::endl; #include <iomanip> usin ...