分析:
将问题转化为重复覆盖问题,DancingLink解决。
代码:
//poj 1084
//sep9
#include <iostream>
using namespace std;
const int maxN=10024;
const int maxL=128;
int L[maxN],R[maxN],U[maxN],D[maxN];
int C[maxN],H[maxN];
int S[maxN],A[maxN],X[maxN];
bool makeup[maxL][maxL];
int cnt,ans;
void build(int r,int c)
{
for(int i=0;i<=c;++i){
U[i]=D[i]=i;
L[i]=i==0?c:i-1;
R[i]=(i+1)%(c+1);
C[i]=i;//colum head's id
S[i]=0;
}
for(int i=1;i<=r;++i)
H[i]=-1;//row head's id;
cnt=c;
}
void init(int n)
{
memset(makeup,false,sizeof(makeup));
int c=1;
for(int len=1;len<=n;++len)
for(int i=1;i+len<=n+1;++i)
for(int j=1;j+len<=n+1;++j){
for(int k=0;k<len;++k){
makeup[(i-1)*(2*n+1)+j+k][c]=true;
makeup[(i-1+len)*(2*n+1)+j+k][c]=true;
makeup[i*n+(i-1)*(n+1)+j+k*(2*n+1)][c]=true;
makeup[i*n+(i-1)*(n+1)+j+k*(2*n+1)+len][c]=true;
}
c++;
}
}
void link(int r,int c)
{
++cnt;
C[cnt]=c;
++S[c];
X[cnt]=r;
D[cnt]=D[c];
U[D[c]]=cnt;
D[c]=cnt;
U[cnt]=c;
if(H[r]<0)
H[r]=L[cnt]=R[cnt]=cnt;
else{
R[cnt]=R[H[r]];
L[cnt]=H[r];
L[R[H[r]]]=cnt;
R[H[r]]=cnt;
}
}
void remove(int c)
{
for(int i=D[c];i!=c;i=D[i]){
L[R[i]]=L[i];
R[L[i]]=R[i];
}
}
void resume(int c)
{
for(int i=D[c];i!=c;i=D[i]){
L[R[i]]=i;
R[L[i]]=i;
}
}
int get_H()
{
bool has[maxL];
memset(has,false,sizeof(has));
int res=0;
for(int i=R[0];i!=0;i=R[i])
if(!has[i]){
++res;
for(int j=D[i];j!=i;j=D[j])
for(int k=R[j];k!=j;k=R[k])
has[C[k]]=true;
}
return res;
}
void dfs(int k)
{
if(R[0]==0){
ans=min(ans,k);
return ;
}
else if(k+get_H()>=ans)
return ;
int c=R[0];
for(int t=R[0],maxx=INT_MAX;t!=0;t=R[t])
if(S[t]<maxx)
maxx=S[t],c=t;
for(int i=D[c];i!=c;i=D[i]){
remove(i);
for(int j=R[i];j!=i;j=R[j]){
remove(j);
--S[C[j]];
}
dfs(k+1);
for(int j=L[i];j!=i;j=L[j]){
resume(j);
++S[C[j]];
}
resume(i);
}
}
int main()
{
int cases,n,row,col;
scanf("%d",&cases);
while(cases--){
scanf("%d",&n);
col=0,row=2*n*(n+1);
for(int i=1;i<=n;++i)
col+=i*i;
build(row,col);
init(n);
int num;
scanf("%d",&num);
bool vis[maxL];//mark square have been destoryed
memset(vis,false,sizeof(vis));
while(num--){
int r;
scanf("%d",&r);
for(int j=1;j<=col;++j)
if(makeup[r][j]&&!vis[j]){
vis[j]=true;
R[L[j]]=R[j];
L[R[j]]=L[j];
}
}
for(int i=1;i<=row;++i)
for(int j=1;j<=col;++j)
if(makeup[i][j]&&!vis[j])
link(i,j);
ans=INT_MAX;
dfs(0);
printf("%d\n",ans);
}
return 0;
}