[ZOJ]3209 Treasure Map 跳舞链 精确覆盖

ZOJ 3209 Treasure Map (DLX精确覆盖)

Your boss once had got many copies of a treasure map. Unfortunately, all the copies are now broken to many rectangular pieces, and what make it worse, he has lost some of the pieces. Luckily, it is possible to figure out the position of each piece in the original map. Now the boss asks you, the talent programmer, to make a complete treasure map with these pieces. You need to make only one complete map and it is not necessary to use all the pieces. But remember, pieces are not allowed to overlap with each other (See sample 2).

Input

The first line of the input contains an integer T (T <= 500), indicating the number of cases.

For each case, the first line contains three integers n m p (1 <= nm <= 30, 1 <= p <= 500), the width and the height of the map, and the number of pieces. Then p lines follow, each consists of four integers x1 y1 x2 y2 (0 <= x1 < x2 <= n, 0 <= y1 < y2 <= m), where (x1, y1) is the coordinate of the lower-left corner of the rectangular piece, and (x2, y2) is the coordinate of the upper-right corner in the original map.

Cases are separated by one blank line.

Output

If you can make a complete map with these pieces, output the least number of pieces you need to achieve this. If it is impossible to make one complete map, just output -1.

Sample Input

3
5 5 1
0 0 5 5

5 5 2
0 0 3 5
2 0 5 5

30 30 5
0 0 30 10
0 10 30 20
0 20 30 30
0 0 15 30
15 0 30 30

Sample Output

1
-1
2

Hint

For sample 1, the only piece is a complete map.

For sample 2, the two pieces may overlap with each other, so you can not make a complete treasure map.

For sample 3, you can make a map by either use the first 3 pieces or the last 2 pieces, and the latter approach one needs less pieces. 

  今天学了一发跳舞链, 名字还挺好听的, 但是花了10min看完发现就是个数据结构优化过后的暴力? 用双向链表来加速dfs过程罢了... 关于跳舞的形容... 可能是我没什么艺术细胞(比如说看不懂毕加索).

  这道题的大意就是说给你一个大矩形和一些小矩形, 然后问能不能用其中的一些小矩形来将大矩形精确覆盖(互不重叠). 那么对于这种精确覆盖的问题一般都是用跳舞链解决. 想想最基础的模型... 用最少的行覆盖所有列, 那么这里用最少的小矩形覆盖所有大矩形, 对应一下就会发现把小矩形看成行, 大矩形看成列, 然后把小矩形覆盖的点映射到这个构造出来的矩形的格子里填作1, 那么就是DLX模板题了. 感觉跳舞链比较裸, 考察的可能是模型转化.

  struct里面递归好慢啊... 还是放弃了struct, 毕竟本身就是暴力, 不能再慢了.

#include
const int maxm = 900;
const int maxn = 5e5;
int T;
int n, m, siz, ans;
int h[maxm], s[maxm];
int col[maxn], le[maxn], ri[maxn], up[maxn], dw[maxn];
inline void init(const int &r, const int &c) {
	n = r, m = c, siz = m;
	for (int i = 0; i <= m; ++ i) {
		s[i] = 0;
		le[i] = i - 1;
		ri[i] = i + 1;
		up[i] = dw[i] = i;
	}
	ri[m] = 0, le[0] = m;
	for (int i = 1; i <= n; ++ i) h[i] = -1;
}
inline void link(const int &r, const int &c) {
	s[col[++ siz] = c] ++;
	dw[siz] = dw[c], up[dw[c]] = siz;
	up[siz] = c, dw[c] = siz;
	if (h[r] < 0) h[r] = le[siz] = ri[siz] = siz;
	else {
		ri[siz] = ri[h[r]], le[ri[h[r]]] = siz;
		le[siz] = h[r], ri[h[r]] = siz;
	}
}
inline void resume(const int &c) {
	for (int i = up[c]; i != c; i = up[i])
		for (int j = le[i]; j != i;j = le[j])
			++ s[col[up[dw[j]] = dw[up[j]] = j]];
	le[ri[c]] = ri[le[c]] = c;
}
inline void remove(const int &c) {
	le[ri[c]] = le[c];
	ri[le[c]] = ri[c];
	for (int i = dw[c]; i != c; i = dw[i])
		for (int j = ri[i]; j != i; j = ri[j]) {
			up[dw[j]] = up[j];
			dw[up[j]] = dw[j];
			s[col[j]] --;
		}
}
void Dance(int d) {
	if (ans != -1 && ans <= d) return;
	if (!ri[0]) {
		if (ans == -1) ans = d;
		else if(d < ans) ans = d;
		return;
	}
	int c = ri[0];
	for (int i = ri[0]; i; i = ri[i])
		if (s[i] < s[c]) c = i;
	remove(c);
	for (int i = dw[c]; i != c; i = dw[i]) {
		for (int j = ri[i]; j != i; j = ri[j])
			remove(col[j]);
		Dance(d + 1);
		for (int j = le[i]; j != i; j = le[j])
			resume(col[j]);
	}
	resume(c);
}
int main() {
	scanf("%d", &T);
	while (T --) {
		int n, m, p, x1, x2, y1, y2;
		scanf("%d%d%d", &n, &m, &p);
		init(p, n * m);
		for (int k = 1; k <= p; ++ k) {
			scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
			for (int i = x1 + 1; i <= x2; ++ i)
				for (int j = y1 + 1; j <= y2; ++ j)
					link(k, (i - 1)  * m + j);
		}
		ans = -1;
		Dance(0);
		printf("%d\n", ans);
	}
}


你可能感兴趣的:(跳舞链)