博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
zoj - 3209 - Treasure Map(精确覆盖DLX)
阅读量:5357 次
发布时间:2019-06-15

本文共 3617 字,大约阅读时间需要 12 分钟。

题意:一个 n x m 的矩形(1 <= n, m <= 30),现给出这个矩形中 p 个(1 <= p <= 500)子矩形的左下角与右下角坐标,问最少用多少个子矩形能够恰好组成这个 n x m 的大矩形。 

题目链接:

——>>这是精确覆盖问题,而DLX正是解决精确覆盖问题的有利武器。。

      模型转换:将原矩形变成一行,作为 DLX 中的列,表示要被覆盖一次且仅一次的目标。子矩形则是行中的一些点,每一个子矩形作为 DLX 的一行,它所覆盖行中的点的位置标为1,其余位标为0,则问题转化为:选出最少的行,使得选出的行中每一列有且仅有一个1,这正是 DLX 解决的问题。。

      注:在往下一层 dfs 的时候,假设检測返回值为真,可别来个return true,这时会中断后面的搜索(非常隐秘地 WA 了几发敲打)。。为了方便,我不要返回值了。。

      为了加快搜索,能够来个剪枝,dfs 时检測当前深度是否 >= 已搜索到的可满足要求的长度。。

#include 
#include
const int MAXN = 30 + 10;const int MAXR = 500 + 10;const int MAXC = 30 * 30 + 10;const int MAXNODE = MAXR * MAXC;const int INF = 0x3f3f3f3f;struct DLX{ int sz; int H[MAXR], S[MAXC]; int row[MAXNODE], col[MAXNODE]; int U[MAXNODE], D[MAXNODE], L[MAXNODE], R[MAXNODE]; int Min; void Init(int n) { for (int i = 0; i <= n; ++i) { U[i] = D[i] = i; L[i] = i - 1; R[i] = i + 1; } L[0] = n; R[n] = 0; sz = n + 1; memset(S, 0, sizeof(S)); memset(H, -1, sizeof(H)); } void Link(const int& r, const int& c) { row[sz] = r; col[sz] = c; D[sz] = D[c]; U[D[c]] = sz; D[c] = sz; U[sz] = c; if (H[r] == -1) { H[r] = L[sz] = R[sz] = sz; } else { R[sz] = R[H[r]]; L[R[H[r]]] = sz; R[H[r]] = sz; L[sz] = H[r]; } S[c]++; sz++; } void Remove(const int& c) { L[R[c]] = L[c]; R[L[c]] = R[c]; for (int i = D[c]; i != c; i = D[i]) { for (int j = R[i]; j != i; j = R[j]) { U[D[j]] = U[j]; D[U[j]] = D[j]; S[col[j]]--; } } } void Restore(const int& c) { for (int i = U[c]; i != c; i = U[i]) { for (int j = L[i]; j != i; j = L[j]) { S[col[j]]++; U[D[j]] = j; D[U[j]] = j; } } L[R[c]] = c; R[L[c]] = c; } void Dfs(int cur) { if (cur >= Min) return; if (R[0] == 0) { if (cur < Min) { Min = cur; } return; } int c = R[0]; for (int i = R[0]; i != 0; i = R[i]) { if (S[i] < S[c]) { c = i; } } Remove(c); for (int i = D[c]; i != c; i = D[i]) { for (int j = R[i]; j != i; j = R[j]) { Remove(col[j]); } Dfs(cur + 1); for (int j = L[i]; j != i; j = L[j]) { Restore(col[j]); } } Restore(c); } void Solve() { Min = INF; Dfs(0); Min != INF ? printf("%d\n", Min) : puts("-1"); }} dlx;int ReadInt(){ int ret = 0; char ch; while ((ch = getchar()) && ch >= '0' && ch <= '9') { ret = ret * 10 + ch - '0'; } return ret;}void Read(){ int n, m, p; scanf("%d%d%d", &n, &m, &p); dlx.Init(n * m); getchar(); for (int i = 1; i <= p; ++i) { int x1 = ReadInt(); int y1 = ReadInt(); int x2 = ReadInt(); int y2 = ReadInt(); for (int j = y1 + 1; j <= y2; ++j) { for (int k = x1 + 1; k <= x2; ++k) { dlx.Link(i, (j - 1) * n + k); } } }}int main(){ int T; scanf("%d", &T); while (T--) { Read(); dlx.Solve(); } return 0;}

转载于:https://www.cnblogs.com/zfyouxi/p/4271644.html

你可能感兴趣的文章
linux下编译复数类型引发的错误:expected unqualified-id before '(' token
查看>>
codeforces 1041A Heist
查看>>
Spring Cloud Stream消费失败后的处理策略(三):使用DLQ队列(RabbitMQ)
查看>>
bzoj1048 [HAOI2007]分割矩阵
查看>>
PKUWC2018 5/6
查看>>
As-If-Serial 理解
查看>>
洛谷P1005 矩阵取数游戏
查看>>
在Silverlight中使用HierarchicalDataTemplate为TreeView实现递归树状结构
查看>>
无线通信基础(一):无线网络演进
查看>>
关于python中带下划线的变量和函数 的意义
查看>>
linux清空日志文件内容 (转)
查看>>
Servlet接收JSP参数乱码问题解决办法
查看>>
Ajax : load()
查看>>
MySQL-EXPLAIN执行计划Extra解释
查看>>
Zookeeper概述
查看>>
Linux自己安装redis扩展
查看>>
luoguP3414 SAC#1 - 组合数
查看>>
图片点击轮播(三)-----2017-04-05
查看>>
直播技术细节3
查看>>
《分布式服务架构:原理、设计于实战》总结
查看>>