A - Treasure Map ZOJ - 3209
思路
- 给我们一个 大矩形,这个矩形的左下角为(0,0),右上角坐标为(n,m)
- 现在又给我们k个小矩形,它左下角坐标为(x1,y1),右上角为(x2,y2),现在我们要用这个k个小矩形的中的一些,来拼凑出的完整的大矩形,注意:拼凑的大矩形不能有重叠部分
- 这个 既然要用 DLX来解决重复覆盖问题,我们先弄明白精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1
- 首先我们考虑:要怎么构造出一个"数据矩形",通过这个数据矩形,把题目的问题转化为精确覆盖问题
- 怎么构造那?,我们注意这句话:“使得集合中每一列都恰好包含一个1”, 对于这个要求我们可以结合题目中的要求:“拼凑的大矩形不能有重叠部分”,不能有重叠那意味着 对于大矩形的 任意一个 1x1单位矩形,只能被覆盖1次,那么我们可以让这个大矩形的 n*m个单位方格,来作为我们要构造的"数据矩形的" 列,这样我们在合理的选择一些行之后,就能使 我们选择出来的集合的每一列,只有一个1出现了 == 等价与 我们把 大矩形 没有重复的 拼凑出来了
- 在注意:“是否能找到一个行的集合”,那么我们考虑,让什么当做“行”,我们把 所给的 小矩形中所出现的 单位方格当做1,其他没有在这个小矩形中 出现的单位矩形 看做0,这样就拼凑一个
“k行 ,m*n列的数据矩形
了”
- 具体做法:
- 我们给大矩形:的每个单位方格 从1到m*n进行 编号,这个每个单位矩形的编号就是它所在的列号,
- 对于k个中的任意一个 小矩形,它都是大矩形的一个子集,那么小矩形 中的单位矩形,必然也是被编了号的,那么小矩形的中的某个单位矩形被编了什么号,那么那个单位小矩形就出现 在那一列,在对应的 数据矩形行、列上就是1,那么剩下的其它位置默认为0,这样就构造好了,之后套模版就行了
代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<map>
#include<string>
#include<cstdio>
#include<cmath>
#include<stack>
void fre() { freopen("A.txt", "r", stdin); freopen("Ans.txt","w",stdout); } void Fre() { freopen("A.txt", "r", stdin);}
#define ios ios::sync_with_stdio(false)
#define Pi acos(-1)
#define pb push_back
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define db double
#define Pir pair<int, int>
#define PIR pair<Pir, Pir>
#define m_p make_pair
#define INF 0x3f3f3f3f
#define mod (ll)(1e9 + 7)
#define for_(i, s, e) for(int i = (ll)(s); i <= (ll)(e); i ++)
#define rep_(i, e, s) for(int i = (ll)(e); i >= (ll)(s); i --)
#define sd(a) scanf("%d", &a)
#define sc(a) scanf("%c", &a)
using namespace std;
const int mxnode = 450010;
const int mxm = 1e3 + 10;
const int mxn = 510;
struct DLX
{
int n, m, size;
int U[mxnode], D[mxnode], L[mxnode], R[mxnode], Row[mxnode], Col[mxnode];
int H[mxn];
int S[mxm];
int ansd, ans[mxn];
void init(int _n, int _m)
{
n = _n, m = _m;
for_(i, 0, m)
{
S[i] = 0;
U[i] = D[i] = i;
L[i] = i - 1;
R[i] = i + 1;
}
R[m] = 0, L[0] = m;
for_(i, 1, n)
H[i] = -1;
size = m;
}
void link(int r, int c)
{
Row[++ size] = r;
Col[size] = c;
S[c] ++;
D[size] = c;
U[size] = U[c];
D[U[c]] = size;
U[c] = size;
if(H[r] == -1)
H[r] = L[size] = R[size] = size;
else
{
L[size] = size - 1;
R[size] = H[r];
R[L[size]] = size;
L[H[r]] = size;
}
}
void remove(int c)
{
R[L[c]] = R[c];
L[R[c]] = L[c];
for(int i = D[c]; i != c; i = D[i])
for(int j = R[i]; j != i; j = R[j])
D[U[j]] = D[j], U[D[j]] = U[j], S[Col[j]] --;
}
void resume(int c)
{
R[L[c]] = c;
L[R[c]] = c;
for(int i = D[c]; i != c; i = D[i])
for(int j = R[i]; j != i; j = R[j])
D[U[j]] = U[D[j]] = j, S[Col[j]] ++;
}
void dance(int d)
{
if(ansd != -1 && ansd <= d) return;
if(R[0] == 0)
{
if(ansd == -1) ansd = d;
else if(ansd > d) ansd = d;
return;
}
int c = R[0];
for(int i = R[0]; i; i = R[i])
if(S[c] > S[i])
c = i;
remove(c);
for(int i = D[c]; i != c; i = D[i])
{
ans[d] = Row[i];
for(int j = R[i]; j != i; j = R[j])
remove(Col[j]);
dance(d + 1);
for(int j = L[i]; j != i; j = L[j])
resume(Col[j]);
}
resume(c);
}
} dl;
int pos[35][35];
void get_pos(int n, int m)
{
int idx = 1;
for_(i, 1, n)
for_(j, 1, m)
pos[i][j] = idx ++;
}
int main()
{
int n, m, t;
int p, x1, y1, x2, y2;
sd(t);
while(t --)
{
scanf("%d %d %d", &n, &m, &p);
dl.init(p, n * m);
get_pos(n, m);
for_(k, 1, p)
{
scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
for_(i, x1+1, x2)
for_(j, y1+1, y2)
dl.link(k, pos[i][j]);
}
dl.ansd = -1;
dl.dance(0);
printf("%d\n", dl.ansd);
}
return 0;
}