本文主要是介绍ZOJ 3209 Treasure Map(精确覆盖问题舞蹈链),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
题目链接:[kuangbin带你飞]专题三 Dancing Links B - Treasure Map
题意
给一矩形和k个小矩形,问选取最小数量为多少的小矩形可以对大矩形进行精确覆盖。
思路
仍然是个模版题,把二维的n*m的大矩形看作是一维的n*m的一条线。k个小矩形同理,那么就转化成01矩阵精确覆盖的问题了。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <vector>using namespace std;const int N = 1009;
const int MAX = 1000009;int U[MAX], D[MAX], L[MAX], R[MAX];//数组模拟链表指向(上下左右)
int C[MAX], M[MAX];//节点所在列与行
int S[N];//储存每列的元素数量
int H[N];//行头指针
int ans;void init(int n, int m)
{for(int i=0; i<=m; i++){L[i+1] = i;R[i] = i+1;U[i] = D[i] = i;S[i] = 0;}for(int i=1; i<=n; i++)H[i] = -1;L[0] = m;R[m] = 0;
}void link(int row, int col, int id)//将节点加入链表
{C[id] = col; M[id] = row;//记录行列U[id] = U[col]; D[U[col]] = id;//上下连接D[id] = col; U[col] = id;if(H[row] == -1)//左右连接(使用表头方便头插)H[row] = L[id] = R[id] = id;else{L[id] = L[H[row]]; R[L[H[row]]] = id;L[H[row]] = id; R[id] = H[row];}S[col]++;
}void remove(int col)//删除列
{R[L[col]] = R[col];L[R[col]] = L[col];for(int i=D[col]; i!=col; i=D[i]){for(int j=R[i]; j!=i; j=R[j]){U[D[j]] = U[j];D[U[j]] = D[j];S[C[j]]--;}}
}void resume(int col)//恢复列(先删的后恢复,后删的先恢复,所以跟remove反向操作)
{R[L[col]] = col;L[R[col]] = col;for(int i=U[col]; i!=col; i=U[i]){for(int j=L[i]; j!=i; j=L[j]){U[D[j]] = j;D[U[j]] = j;S[C[j]]++;}}
}void dance(int k)
{if(ans!=-1 && k>=ans)return;if(!R[0]){ans = k;return;}int col = R[0];for(int i=R[0]; i!=0; i=R[i])if(S[i] < S[col])col = i;remove(col);for(int i=D[col]; i!=col; i=D[i]){for(int j=R[i]; j!=i; j=R[j])remove(C[j]);dance(k+1);for(int j=L[i]; j!=i; j=L[j])resume(C[j]);}resume(col);
}int main()
{int n, m, k, T;scanf("%d", &T);while(T--){scanf("%d%d%d", &n, &m, &k);init(k, n*m);int id = n*m+1;for(int i=1; i<=k; i++){int x1, x2, y1, y2;scanf("%d%d%d%d", &x1, &y1, &x2, &y2);for(int x=x1+1; x<=x2; x++)for(int y=y1+1; y<=y2; y++)link(i, y+(x-1)*m, id++);}ans = -1;dance(0);printf("%d\n", ans);}return 0;
}
这篇关于ZOJ 3209 Treasure Map(精确覆盖问题舞蹈链)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!