ZOJ 3209 Treasure Map(Dancing Links)(精确覆盖问题)
2016-01-18 17:41
555 查看
Treasure Map
题目链接:
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3209解题思路:
题目大意:给你一个n*m的矩形,有p个小矩形,问你用这些小矩形(不允许重复)最多可以拼多少个n*m的矩形。
算法思想:
Dancing Links.
把每个格子当成一个列,然后覆盖所有格子。问题就转为了:精确覆盖问题。
AC代码:
#include <iostream> #include <cstdio> using namespace std; const int maxnode = 100010; const int maxm = 1010; const int maxn = 1010; struct DLX{ int n,m,len; int U[maxnode],D[maxnode],R[maxnode],L[maxnode],Row[maxnode],Col[maxnode]; int H[maxn];//行头结点 int S[maxm];//每列有多少个结点 int ansd,ans[maxn];//如果有答案,则选了ansd行,具体是哪几行放在ans[]数组里面,ans[0~ansd-1] void init(int _n,int _m){ n = _n;m = _m; for(int i = 0; i <= m; i++){ S[i] = 0; U[i] = D[i] = i;//初始状态时,上下都指向自己 L[i] = i-1; R[i] = i+1; } R[m] = 0,L[0] = m; len = m;//编号,每列都有一个头结点,编号1~m for(int i = 1; i <= n; i++) H[i] = -1;//每一行的头结点 } void link(int r,int c){//第r行,第c列 ++S[Col[++len]=c];//第len个节点所在的列为c,当前列的结点数++ Row[len] = r;//第len个结点行位置为r D[len] = D[c]; U[D[c]] = len; U[len] = c; D[c] = len; if(H[r] < 0) H[r] = L[len] = R[len] = len; else{ R[len] = R[H[r]]; L[R[H[r]]] = len; L[len] = H[r]; R[H[r]] = len; } } void del(int c){//删除结点c,以及c上下结点所在的行 //每次调用这个函数,都是从列头节点开始向下删除,这里c也可以理解为第c列 //因为第c列的列头节点编号为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 resume(int c){//回复结点c,以及c上下节点所在的行(同上,也可以理解为从第c列的头节点开始恢复 for(int i = U[c]; i != c; i = U[i]){ for(int j = L[i]; j != i; j = L[j]){ ++S[Col[U[D[j]]=D[U[j]]=j]]; } } L[R[c]] = R[L[c]] = c; } void dance(int d){//递归深度 //剪枝 if(ansd != -1 && ansd <= d) return; if(R[0] == 0){ if(ansd == -1) ansd = d; else if(d < ansd) ansd = d; return ; } int c = R[0]; for(int i = R[0]; i != 0; i = R[i]){ if(S[i] < S[c]) c = i; } del(c);//找到结点数最少的列,当前元素不是原图上0,1的节点,而是列头节点 for(int i = D[c]; i != c; i = D[i]){ ans[d] = Row[i];//列头节点下面的一个节点 for(int j = R[i]; j != i; j = R[j]) del(Col[j]); dance(d+1); for(int j = L[i]; j != i; j = L[j]) resume(Col[j]); } resume(c); } }; DLX head; int main(){ int T; scanf("%d",&T); while(T--){ int n,m,p; scanf("%d%d%d",&n,&m,&p); head.init(p,n*m); int x1,y1,x2,y2; 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++){ head.link(k,(i-1)*m+j); } } } head.ansd = -1; head.dance(0); printf("%d\n",head.ansd); } return 0; }
相关文章推荐
- HUST 1017 Exact cover
- HUST 1017 Exact cover(Dancing Links)(精确覆盖问题)
- 一切不以Eng 抑或 官网 reference 为参考的 例子都是扯淡
- External Links Module 友情链接模块
- useful open source links
- x
- 跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题
- 通用链接universal links中遇到的问题
- hust1017Exact cover(Dancing Links)
- iPhone开发 – iPhonAn App ID with Identifier 'XX.XX' is not available. Please enter a different string
- FZU 1686 神龙的难题(重复覆盖|Dancing Links)
- hdu 2295 Radar(重复覆盖问题)
- 创建通用链接
- Universal links(页面跳转app)
- Linux中硬链接和软连接的介绍
- about recommender system
- 复制集要点
- MATLAB入门
- 执行大事务导致订阅数据库延迟的处理方法
- mysql查询分组归类函数-group_concat,通常与group_by一起使用