题意:n*n的矩形阵(n<=5),由2*n*(n+1)根火柴构成,那么其中会有很多诸如边长为1,为2...为n的正方形,现在可以拿走一些火柴,那么就会有一些正方形被破坏掉。问,在已经拿走一些火柴的情况下,还需要拿走至少多少根就可以把所有的正方形破坏掉。

题解:可以用dancing links做,让火柴做为行,让所有的正方形作为列,且如果i火柴能让j正方形破坏掉,就让第i行第j列为1,然后做一次可重复的覆盖,取最小值便可以得到答案。另外,涉及两个优化,

   1、最优化剪枝,即最好情况下也不会比当前最优值更优的剪枝。

   2、不必一开始就将所有的火柴棍与正方形的对应关系加入到DLX中,应该在读完所有数据之后,判断哪些正方形已经被删除了(即该列无效),只加入有效的结点。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 const int inf=1<<30;
  6 const int NUM=100*60;
  7 int cnt,L[NUM],R[NUM],S[NUM],D[NUM],U[NUM],C[NUM],O[NUM],H[NUM],X[NUM];
  8 /*
  9     NUM:最大结点数
 10     U,D,L,R:上下左右结点
 11     C:列的头指针位置
 12     O:储存答案
 13     X:与O配合代表第几行(X[O[i]]])
 14     通过link(r,c)加点,dfs(0)运算
 15 */
 16 void remove(int c)
 17 {
 18     for(int i=D[c];i!=c;i=D[i])
 19     {
 20         L[R[i]]=L[i];
 21         R[L[i]]=R[i];
 22     }
 23 }
 24 void resume(int c)
 25 {
 26     for(int i=D[c];i!=c;i=D[i])
 27     {
 28         L[R[i]]=i;
 29         R[L[i]]=i;
 30     }
 31 }
 32 int geth()
 33 {
 34     bool has[80];
 35     memset(has, false, sizeof(has));
 36     int res=0;
 37     for(int i=R[0]; i!=0; i=R[i])
 38         if(!has[i])
 39         {
 40             res++;
 41             for(int j=D[i]; j!=i; j=D[j])
 42                 for(int k=R[j]; k!=j; k=R[k])
 43                     has[C[k]]=true;
 44         }
 45     return res;
 46 }
 47 int ans;
 48 void dfs(int k)
 49 {
 50     if(!R[0])
 51     {
 52         ans=min(k,ans);
 53         return;
 54     }
 55     else if(k+geth()>=ans)
 56         return;
 57     int c=R[0];
 58     for(int t=R[0],ms=inf; t!=0; t=R[t])
 59         if(S[t]<ms)
 60             ms=S[t],c=t;
 61     for(int i=D[c];i!=c;i=D[i])
 62     {
 63         remove(i);
 64         for(int j=R[i]; j!=i; j=R[j])
 65         {
 66             remove(j);
 67             S[C[j]]--;
 68         }
 69         dfs(k+1);
 70         for(int j=L[i]; j!=i; j=L[j])
 71         {
 72             resume(j);
 73             S[C[j]]++;
 74         }
 75         resume(i);
 76     }
 77 }
 78 void build(int r,int c)
 79 {
 80     for(int i=0;i<=c;i++)
 81     {
 82         U[i]=D[i]=i;
 83         L[i+1]=i;
 84         R[i]=i+1;
 85         C[i]=i;
 86         S[i]=0;
 87     }
 88     R[cnt=c]=0;
 89     while(r)
 90         H[r--]=-1;
 91 }
 92 void link(int r,int c)
 93 {
 94     ++S[C[++cnt]=c];
 95     X[cnt]=r;
 96     D[cnt]=D[c];
 97     U[D[c]]=cnt;
 98     U[cnt]=c;
 99     D[c]=cnt;
100     if(H[r]<0)
101         H[r]=L[cnt]=R[cnt]=cnt;
102     else
103     {
104         R[cnt]=R[H[r]];
105         L[R[H[r]]]=cnt;
106         L[cnt]=H[r];
107         R[H[r]]=cnt;
108     }
109 }
110 bool mark[80][80];
111 void init(int n)
112 {
113     memset(mark,false,sizeof(mark));
114     int i,j,k,si,num=0,c=1;
115     for(si=1;si<=n;si++)
116     {
117         for(i=1;i<=n-si+1;i++)
118         {
119             for(j=1;j<=n-si+1;j++)
120             {
121                 for(k=0;k<si;k++)
122                 {
123                     mark[(i-1)*(2*n+1)+j+k][c]=true;
124                     mark[(i-1+si)*(2*n+1)+j+k][c]=true;
125                     mark[i*n+(i-1)*(n+1)+j+k*(2*n+1)][c]=true;
126                     mark[i*n+(i-1)*(n+1)+j+k*(2*n+1)+si][c]=true;
127                 }
128                 c++;
129             }
130         }
131     }
132 }
133 int main()
134 {
135     int T,n;
136     for(scanf("%d",&T);T;T--)
137     {
138         scanf("%d",&n);
139         int num,row=2*n*(n+1),col=0;
140         for(int i=1;i<=n;i++)
141             col+=i*i;
142         build(row,col);
143         init(n);
144         scanf("%d",&num);
145         bool vis[80];
146         memset(vis,false,sizeof(vis));
147         for(int i=0;i<num;i++)
148         {
149             int r;
150             scanf("%d",&r);
151             for(int j=1;j<=col;j++)
152             {
153                 if(mark[r][j])
154                 {
155                     if(!vis[j])
156                     {
157                         vis[j]=true;
158                         R[L[j]]=R[j];
159                         L[R[j]]=L[j];
160                         R[j]=L[j]=0;
161                     }
162                 }
163             }
164         }
165         for(int i=1;i<=row;i++)
166             for(int j=1;j<=col;j++)
167                 if(mark[i][j]&&!vis[j])
168                     link(i,j);
169         ans=100000;
170         dfs(0);
171         printf("%d\n",ans);
172     }
173     return 0;
174 }