题意:用p(500)个矩形(给出左下角和右上角)拼成一个n×m(30×30)的大矩形,输出最少使用个数。
把n×m每个格子都看成交叉十字循环双向链的一列,于是有n×m列,每个矩形都覆盖了一些列,于是就转化成01矩阵的精确覆盖,直接上模板。
建图的时候注意细节
#include<cstdio>
const int N=505005,INF=0x3f3f3f3f;
struct DLX
{
int L[N],R[N],U[N],D[N],row[N],col[N];
int H[505];
int ansd,ans[505];
int s[1005];
int tot,n,m;
void init(int _n,int _m)
{
n=_n; m=_m;
tot=m;
for (int i=0;i<=m;i++) L[i]=i-1,R[i]=i+1,U[i]=i,D[i]=i,s[i]=0;
L[0]=m; R[m]=0;
for (int i=1;i<=n;i++) H[i]=-1;
}
void link(int i,int j)
{
s[j]++;
++tot;
row[tot]=i; col[tot]=j;
U[tot]=U[j]; D[tot]=j; D[U[j]]=tot; U[j]=tot;
if (H[i]<0)
{
H[i]=tot; L[tot]=tot; R[tot]=tot;
}
else
{
L[tot]=L[H[i]]; R[tot]=H[i]; R[L[H[i]]]=tot; L[H[i]]=tot;
}
}
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])
{
s[col[j]]--;
D[U[j]]=D[j];
U[D[j]]=U[j];
}
}
void resume(int c)
{
R[L[c]]=c; L[R[c]]=c;
for (int i=U[c];i!=c;i=U[i])
for (int j=L[i];j!=i;j=L[j])
{
s[col[j]]++;
D[U[j]]=j;
U[D[j]]=j;
}
}
void dfs(int d)
{
if (d-1>=ansd) return ;
if (R[0]==0)
{
if (d-1<ansd) ansd=d-1;
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]);
dfs(d+1);
for (int j=L[i];j!=i;j=L[j]) resume(col[j]);
}
resume(c);
return;
}
}g;
int main()
{
int t;
int n,m,p,sx,sy,ex,ey;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&p);
g.init(p,n*m);
for (int k=1;k<=p;k++)
{
scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
for (int i=sx+1;i<=ex;i++)
for (int j=sy+1;j<=ey;j++) g.link(k,(i-1)*m+j);
}
g.ansd=INF;
g.dfs(1);
if (g.ansd<INF) printf("%d\n",g.ansd);
else printf("-1\n");
}
}