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.
Author: HANG, Hang
Source: The 6th Zhejiang Provincial Collegiate Programming Contest
DancingLinksX的题目
题意给你一些碎的地图
然后你知道这个碎块属于大地图的哪部分
让你用其中的尽量少的一些拼出大地图
碎块作为行,大地图的每一个小的单元格作为列
建图即可
这里注意dance即dfs一定要减掉超过目前最优解的情况
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int MN=505;
const int MM=35*35;
const int MNN=MN*MM+MM; //最大点数
struct DLX
{
int n,m,si;//n行数m列数si目前有的节点数
//十字链表组成部分
int U[MNN],D[MNN],L[MNN],R[MNN],Row[MNN],Col[MNN];
//第i个结点的U向上指针D下L左R右,所在位置Row行Col列
int H[MN],S[MM]; //记录行的选择情况和列的覆盖情况
int ansd,ans[MN];
void init(int _n,int _m) //初始化空表
{
n=_n;
m=_m;
for(int i=0;i<=m;i++) //初始化第一横行(表头)
{
S[i]=0;
U[i]=D[i]=i; //目前纵向的链是空的
L[i]=i-1;
R[i]=i+1; //横向的连起来
}
R[m]=0;L[0]=m;
si=m; //目前用了前0~m个结点
for(int i=1;i<=n;i++)
H[i]=-1;
}
void link(int r,int c) //插入点(r,c)
{
//cout<<"link "<<r<<" "<<c<<endl;
++S[Col[++si]=c]; //si++;Col[si]=c;S[c]++;
Row[si]=r;
D[si]=D[c];
U[D[c]]=si;
U[si]=c;
D[c]=si;
if(H[r]<0)
H[r]=L[si]=R[si]=si;
else
{
R[si]=R[H[r]];
L[R[H[r]]]=si;
L[si]=H[r];
R[H[r]]=si;
}
}
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[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])
++S[Col[U[D[j]]=D[U[j]]=j]];
L[R[c]]=R[L[c]]=c;
}
void dance(int d) //选取了d行
{
if(ansd!=-1&&d>=ansd) //特别注意这里剪枝
return;
if(R[0]==0)//全部覆盖了
{
//全覆盖了之后的操作
//if(ansd==-1) 能进来的d值显然符合上下两个条件
ansd=d;
//else 但是不注释掉这些速度更快……
// ansd=min(ansd,d);
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])
{
//ans[d]=Row[i];
for(int j=R[i];j!= i;j=R[j])
remove(Col[j]);
dance(d+1);
//cout<<"R0 "<<R[0]<<endl;
for(int j=L[i];j!=i;j=L[j])
resume(Col[j]);
}
resume(c);
return;
}
}dlx;
int main()
{
int t,n,m,p;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&p);
dlx.init(p,n*m);
for(int ii=1;ii<=p;ii++)
{
int x,xx,y,yy;
scanf("%d%d%d%d",&x,&y,&xx,&yy);
for(int i=x+1;i<=xx;i++)
for(int j=y+1;j<=yy;j++)
dlx.link(ii,(i-1)*m+j);
}
dlx.ansd=-1;
dlx.dance(0);
printf("%d\n",dlx.ansd);
}
return 0;
}