POJ 1691 Painting A Board(状态压缩DP + 记忆化搜索)
题意:
有一个矩形框由n个小的矩形组成,现在要把每个矩形涂上一种颜色c(可相同可不同,如下图)。为了保证涂的质量,涂每个小矩阵有一个条件,就是位于它上面,并且与它有连接的小矩形必须先涂好。当然满足条件的同一种颜色可以一起涂,问最少需要多少把刷子(每把刷子一种颜色)。
黑书 146 :平板涂色
思路:
1. 矩形的数量不超过 15,所以自然的联想到利用状态压缩去解决问题,并且为了解决无后效性,还必须增加一维,dp[i][s] 表示以 i 结尾的状态 s 的最小;
2. 首先预处理,矩形 i 上面的矩形编号,为下面的解题作个很好的铺垫;
3. 剩下的工作就是枚举:i 前一个所刷的矩形,思路很简单就不多述了。注意循环的时候 s 放在前面,这样才能保证求得的结果不相互影响;
#include <iostream>
#include <algorithm>
using namespace std;
const int INFS = 0x3FFFFFFF;
struct POINT {
int x1, y1, x2, y2;
int color;
} rect[20] ;
int up[20], dp[15][1<<15];
bool judge(int i, int j) {
// whether j is upper to i
if (rect[j].x2 != rect[i].x1) return false;
if (rect[j].y2 <= rect[i].y1) return false;
if (rect[j].y1 >= rect[i].y2) return false;
return true;
}
int workout(int n) {
for (int i = 0; i < n; i++) {
up[i] = 0;
for (int j = 0; j < n; j++)
if (judge(i, j)) up[i] |= (1<<j);
}
int ENDS = (1<<n) - 1;
for (int i = 0; i < n; i++)
for (int s = 0; s <= ENDS; s++)
dp[i][s] = INFS;
for (int i = 0; i < n; i++)
if (up[i] == 0) dp[i][1<<i] = 1;
for (int s = 0; s <= ENDS; s++) {
for (int i = 0; i < n; i++) {
if (s & (1<<i)) continue;
if ((s & up[i]) != up[i]) continue;
for (int j = 0; j < n; j++) {
if (!(s & (1<<j))) continue;
int now = s | (1<<i);
int value = dp[j][s];
if (rect[i].color != rect[j].color) value += 1;
dp[i][now] = min(dp[i][now], value);
}
}
}
int ans = INFS;
for (int i = 0; i < n; i++)
ans = min(ans, dp[i][ENDS]);
return ans;
}
int main() {
int cases;
scanf("%d", &cases);
while (cases--) {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d%d%d%d%d", &rect[i].x1, &rect[i].y1, &rect[i].x2, &rect[i].y2, &rect[i].color);
printf("%d\n", workout(n));
}
return 0;
}
-------------------------------------------------------
kedebug
Department of Computer Science and Engineering,
Shanghai Jiao Tong University
E-mail: kedebug0@gmail.com
GitHub: http://github.com/kedebug
-------------------------------------------------------