传送门:​​点击打开链接​

题意:先告诉一个一个矩阵大小n*m和有多少个矩形p,然后告诉每个矩形所在的左下角和右上角的坐标,要求矩形不能有重叠部分,求覆盖矩阵至少需要多少个矩形。

思路:DLX精确覆盖,列表示每个点,行表示矩形,那么每次将矩形和矩形中的点对应起来,需要选出一些行使得所有的列都被覆盖,这样题目就转换完成了

#include<map>
#include<set>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck printf("fuck")
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;

const int MX = 1000 + 5;
const int MN = 1000000 + 5;
const int INF = 0x3f3f3f3f;

struct DLX {
int m, n, ans;
int H[MX], S[MX], vis[MX];
int Row[MN], Col[MN], rear;
int L[MN], R[MN], U[MN], D[MN];

void Init(int _m, int _n) {
m = _m; n = _n;
rear = n; ans = INF;
for(int i = 0; i <= n; i++) {
S[i] = 0;
L[i] = i - 1;
R[i] = i + 1;
U[i] = D[i] = i;
}
L[0] = n; R[n] = 0;
for(int i = 1; i <= m; i++) {
H[i] = -1;
}
}

void Link(int r, int c) {
int rt = ++rear;
Row[rt] = r; Col[rt] = c; S[c]++;

D[rt] = D[c]; U[D[c]] = rt;
U[rt] = c; D[c] = rt;
if(H[r] == -1) {
H[r] = L[rt] = R[rt] = rt;
} else {
int id = H[r];
R[rt] = R[id]; L[R[id]] = rt;
L[rt] = id; R[id] = rt;
}
}

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) {
for(int i = U[c]; i != c; i = U[i]) {
for(int j = L[i]; j != i; j = L[j]) {
D[U[j]] = U[D[j]] = j;
S[Col[j]]++;
}
}
R[L[c]] = L[R[c]] = c;
}

int h() {
int ret = 0;
memset(vis, 0, sizeof(vis));
for(int c = R[0]; c != 0; c = R[c]) {
if(!vis[c]) {
ret++;
vis[c] = 1;
for(int i = D[c]; i != c; i = D[i]) {
for(int j = R[i]; j != i; j = R[j]) {
vis[Col[j]] = 1;
}
}
}
}
return ret;
}

void Dance(int cnt) {
if(cnt + h() >= ans) return;
if(R[0] == 0) {
ans = min(ans, cnt);
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]);
Dance(cnt + 1);
for(int j = L[i]; j != i; j = L[j]) Resume(Col[j]);
}
Resume(c);
}
} G;

int main() {
int T, m, n, p; //FIN;
scanf("%d", &T);
while(T--) {
scanf("%d%d%d", &m, &n, &p);
G.Init(p, m * n);
for(int i = 1; i <= p; i++) {
int x1, y1, x2, 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++) {
G.Link(i, (x - 1)*n + y);
}
}
}
G.Dance(0);
printf("%d\n", G.ans == INF ? -1 : G.ans);
}
return 0;
}