Your boss once had got many copies of a treasure map. Unfortunately, all the copies are now broken to many rectangular pieces, and what make it worse, he has lost some of the pieces. Luckily, it is possible to figure out the position of each piece in the original map. Now the boss asks you, the talent programmer, to make a complete treasure map with these pieces. You need to make only one complete map and it is not necessary to use all the pieces. But remember, pieces are not allowed to overlap with each other (See sample 2).
Input
The first line of the input contains an integer T (T <= 500), indicating the number of cases.
For each case, the first line contains three integers n m p (1 <= n, m <= 30, 1 <= p <= 500), the width and the height of the map, and the number of pieces. Then p lines follow, each consists of four integers x1 y1 x2 y2 (0 <= x1 < x2 <= n, 0 <= y1 < y2 <= m), where (x1, y1) is the coordinate of the lower-left corner of the rectangular piece, and (x2, y2) is the coordinate of the upper-right corner in the original map.
Cases are separated by one blank line.
Output
If you can make a complete map with these pieces, output the least number of pieces you need to achieve this. If it is impossible to make one complete map, just output -1.
Sample Input
3
5 5 1
0 0 5 5
5 5 2
0 0 3 5
2 0 5 5
30 30 5
0 0 30 10
0 10 30 20
0 20 30 30
0 0 15 30
15 0 30 30
Sample Output
1
-1
2
Hint
For sample 1, the only piece is a complete map.
For sample 2, the two pieces may overlap with each other, so you can not make a complete treasure map.
For sample 3, you can make a map by either use the first 3 pieces or the last 2 pieces, and the latter approach one needs less pieces.
舞蹈链第一题,主要学会怎么写舞蹈链,这道题是舞蹈链精确覆盖摸板题。。。
用数组和指针各实现了一遍;
数组版本:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
//最大行数
const int MN = 1005;
//最大列数
const int MM = 1005;
//最大点数
const int MNN = 1e5 + 5 + MM;
struct DLX
{
//一共n行m列,s个节点
int n,m,s;
//交叉十字链表组成部分
//第i个节点的上U下D左L右R,所在位置row行col列
int U[MNN],D[MNN],L[MNN],R[MNN],row[MNN],col[MNN];
//H数组记录行选择指针,S数组记录覆盖个数
int H[MN],S[MM];
//res记录行个数,ans数组记录可行解
int res,ans[MN];
//初始化空表
void init(int x,int y)
{
n = x,m = y;
//其中0节点作为head节点,其他作为列首节点
for(int i = 0;i <= m;++i){
U[i] = D[i] = i;
L[i] = i - 1;
R[i] = i + 1;
}
R[m] = 0;L[0] = m;
s = m;
memset(S,0,sizeof(S));
memset(H,-1,sizeof(H));
}
void Insert(int r,int c)
{
//节点数加一,设置s节点所处位置,以及S列覆盖个数加一
s++;row[s] = r;col[s] = c;S[c]++;
//将s节点插入对应列中
D[s] = D[c];U[D[c]] = s;
U[s] = c;D[c] = s;
if(H[r] < 0){//如果该行没有元素,H[r]标记该行起始节点
H[r] = L[s] = R[s] = s;
}else{
//将该节点插入该行第一个节点后面
R[s] = R[H[r]];
L[R[H[r]]] = s;
L[s] = H[r];
R[H[r]] = s;
}
}
void Remove(int 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数组减一
--S[col[j]];
}
}
}
void resume(int c)
{
//恢复c列
for(int i = U[c];i != c;i = U[i]){//枚举该列元素
for(int j = L[i];j != i;j = L[j]){
U[D[j]] = j;D[U[j]] = j;
++S[col[j]];
}
}
L[R[c]] = c;R[L[c]] = c;
}
bool dance(int deep)
{
if(res < deep) return false;
//当矩阵为空时,说明找到一个可行解,算法终止
if(R[0] == 0){
res = min(res,deep);
return true;
}
//找到节点数最少的列,枚举这列上的所有行
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]){
//将行r放入当前解
ans[deep] = row[i];
//行上节点对应的列上进行删除
for(int j = R[i];j != i;j = R[j])
Remove(col[j]);
//进入下一层
dance(deep + 1);
//对行上的节点对应的列进行恢复
for(int j = L[i];j != i;j = L[j])
resume(col[j]);
}
//恢复节点数最少列
resume(c);
return false;
}
}dlx;
int n,m,p;
//inline int read() {
// char ch = getchar(); int x = 0, f = 1;
// while(ch < '0' || ch > '9') {
// if(ch == '-') f = -1;
// ch = getchar();
// } while('0' <= ch && ch <= '9') {
// x = x * 10 + ch - '0';
// ch = getchar();
// } return x * f;
//}
int main()
{
int t;
scanf("%d",&t);
//t = read();
while(t--)
{
scanf("%d %d %d",&n,&m,&p);
//n = read();m = read();p = read();
dlx.init(p - 1,n * m);
for(int i = 0;i < p;++i){
int x1,y1,x2,y2;
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
//x1 = read(),y1 = read(),x2 = read(),y2 = read();
for(int j = x1;j < x2;++j){
for(int k = y1;k < y2;++k){
dlx.Insert(i,n * k + j + 1);
}
}
}
dlx.res = inf;
dlx.dance(0);
if(dlx.res == inf){
printf("-1\n");
}else{
printf("%d\n",dlx.res);
}
}
return 0;
}
指针版:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int MAX_N = 31;
const int MAX_M = 31;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
//交叉十字链表节点
struct DLX_node{
DLX_node *L,*R,*U,*D;
int col;
};
class DLX{
public:
DLX(){
for(int i = 0;i < MAX_N * MAX_M;++i){
column[i].col = i;
}
}
//初始化链表
void init(int n,int m);
void dance(int deep);
void input(int x1,int y1,int x2,int y2);
int getans() { return ans;}
private:
int n,m;
int ans;
int cnt;
int scnt;//节点个数,不包括列首节点
DLX_node head;//头结点
DLX_node column[MAX_N * MAX_M];//列首
DLX_node table[100000];//数据表
DLX_node *get_dlx_node();
void init_node(DLX_node *tmp);
void Insert(DLX_node *l,DLX_node *u,DLX_node *insert_node);
void Remove(DLX_node *c);
void resume(DLX_node *c);
};
void DLX::init(int n,int m)
{
this -> n = n;this -> m = m;
ans = inf;scnt = 0;
init_node(&head);
for(int i = 0;i < n * m;++i){
init_node(&column[i]);
Insert(&head,&column[i],&column[i]);
}
}
void DLX::init_node(DLX_node *n)
{
n -> L = n;n -> R = n;
n -> U = n;n -> D = n;
}
DLX_node *DLX::get_dlx_node()
{
init_node(&table[scnt]);
return &table[scnt++];
}
//l为行最左边的元素,u为列首元素
void DLX::Insert(DLX_node *l,DLX_node *u,DLX_node *insert_node)
{
insert_node -> L = l -> L;l -> L = insert_node;
insert_node -> R = l;insert_node -> L -> R = insert_node;
insert_node -> U = u -> U;u -> U = insert_node;
insert_node -> D = u;insert_node -> U -> D = insert_node;
insert_node -> col = u -> col;
}
void DLX::Remove(DLX_node *c)
{
c -> L -> R = c -> R;c -> R -> L = c -> L;
for(DLX_node *i = c -> D;i != c;i = i -> D){
for(DLX_node *j = i -> R;j != i;j = j -> R){
j -> D -> U = j -> U;
j -> U -> D = j -> D;
}
}
}
void DLX::resume(DLX_node *c)
{
c -> R -> L = c;
c -> L -> R = c;
for(DLX_node *i = c -> U;i != c;i = i -> U){
for(DLX_node *j = i -> R;j != i;j = j -> R){
j -> D -> U = j;
j -> U -> D = j;
}
}
}
void DLX::input(int x1,int y1,int x2,int y2)
{
DLX_node *l = get_dlx_node();
for(int i = x1;i < x2;++i){
for(int j = y1;j < y2;++j){
if(i == x1 && j == y1){
Insert(l,&column[i * m + j],l);
}else{
Insert(l,&column[i * m + j],get_dlx_node());
}
}
}
}
void DLX::dance(int deep)
{
if(head.R == &head){
ans = min(ans,deep);
return ;
}
DLX_node *c = head.R;
Remove(c);
for(DLX_node *i = c -> D;i != c;i = i -> D){
for(DLX_node *j = i -> R;j != i;j = j -> R)
Remove(&column[j -> col]);
dance(deep + 1);
for(DLX_node *j = i -> L;j != i;j = j -> L)
resume(&column[j -> col]);
}
resume(c);
}
DLX dlx;
int n,m,p;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d %d %d",&n,&m,&p);
dlx.init(n,m);
for(int i = 0;i < p;++i)
{
int x1,y1,x2,y2;
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
dlx.input(x1,y1,x2,y2);
}
dlx.dance(0);
int ans = dlx.getans();
if(ans == inf){
printf("-1\n");
}else{
printf("%d\n",ans);
}
}
return 0;
}