题意 : 给你一个大小为 n * m 的矩形 , 坐标是( 0 , 0 ) ~ ( n , m ) 。然后给你 p 个小矩形 , 坐标是( x1 , y1 ) ~ ( x2 , y2 ) , 你选择最小的几个矩形 , 使得这些矩形可以覆盖整个矩形 , 并且互相不会重叠 。( n , m <= 30 )
思路 : Dancing Links 的精确覆盖问题 。
我们将 n * m 的矩形分成 n * m 个小正方形 ,那么我们只要保证每个小正方形被覆盖且只被覆盖一次即可 。
那么列表示每个小正方形 , 行表示你选择的矩形 , 如果选择这个矩形可以覆盖某个小正方形 , 则对应的格子是1 , 否则对应的格子是 0
最多有 30 * 30 = 900 列 ,最多有 500 行
#include<cstdio>
#define inf 10000000
#define N 1005
#define M 1024*505
int U[M],D[M],L[M],R[M],C[M];//C代表M所属的列,U,D,L,R为一个元素的上下左右指针
int H[505];//H是水平循环链表的头指针
int S[1005];//S代表每一列的元素个数
int size,n,m,p,ans;
void Link(int r,int c)
{
U[size] = c;
D[size] = D[c];
U[D[c]] = size;
D[c] = size;
if (H[r] < 0)
H[r] = L[size] = R[size] = size;
else {
L[size] = H[r];
R[size] = R[H[r]];
L[R[H[r]]] = size;
R[H[r]] = size;
}
S[c]++;
// row[size] = r ;
C[size++] = c;
}
void Remove(int c) { //删除c列及相应的行
int i, j;
R[L[c]] = R[c];
L[R[c]] = L[c];
for (i = D[c]; i != c; i = D[i]) {
for (j = R[i]; j != i; j = R[j]) {
U[D[j]] = U[j];
D[U[j]] = D[j];
S[C[j]]--;
}
}
}
void Resume(int c) { //恢复c列
int i, j;
R[L[c]] = c;
L[R[c]] = c;
for (i = D[c]; i != c; i = D[i]) {
for (j = R[i]; j != i; j = R[j]) {
U[D[j]] = j;
D[U[j]] = j;
S[C[j]]++;
}
}
}
void Dance(int now) { //舞蹈链
if (R[0] == 0) //输出答案
{
if(ans > now) //更新最小答案 ;
ans = now ;
return ;
}
int i, j, temp, c;
for (temp=inf,i = R[0]; i; i = R[i]) {
if(S[i]<temp)
{
temp=S[i];
c=i;
}
}
Remove(c);
for(i=D[c];i!=c;i=D[i])
{ // O[now]=row[i] ; //记录答案 ;
for(j=R[i];j!=i;j=R[j])
Remove(C[j]);
Dance(now+1) ;
for(j=L[i];j!=i;j=L[j])
Resume(C[j]);
}
Resume(c);
}
void init(int n,int m){
int i;
for (i = 1; i <= n; i++)
H[i] = -1;
for (i = 0; i <= m; i++) {
S[i] = 0;
L[i + 1] = i;
R[i] = i + 1;
U[i] = D[i] = i;
}
R[m] = 0;
size = m + 1;
}
int main()
{
int t ,n,m,p,x,y,xx,yy;
scanf("%d",&t) ;
while(t--)
{
scanf("%d%d%d",&n,&m,&p) ;
init(p,n*m) ;
for(int k = 1 ; k <= p ; k++)
{
scanf("%d%d%d%d",&x,&y,&xx,&yy) ;
for(int i = x ; i < xx ; i++)
for(int j = y; j < yy ; j++)
{
int tmp = i*m+j+1 ;
Link(k,tmp) ;
// printf("%d ",tmp) ;
}
// puts("") ;
}
ans = inf ;
Dance(0);
if(ans != inf)
printf("%d\n",ans) ;
else printf("-1\n");
}
return 0;
}