先考虑小正方形,再考虑大正方形。当前深度加去掉目前正方形的消耗超过最大深度就可以剪枝。
利用了二进制储存,非常巧妙。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
int n,k,t,sqr_cnt,edge_cnt,maxd;
LL place(int x){return(LL)1<<(x-1);}
int hor(int r,int c){return r*(2*n+1)+c+1;}
int ver(int r,int c){return r*(2*n+1)+c+1+n;}
LL sqr[61],one_sqr[10][10];
void init()
{
cin>>n;
edge_cnt=2*n*(n+1);
sqr_cnt=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
sqr[sqr_cnt]=place(hor(i,j))|place(hor(i+1,j))|place(ver(i,j))|place(ver(i,j+1));
one_sqr[i][j]=sqr[sqr_cnt++];
}
}
for(int sz=2;sz<=n;sz++)
{
for(int i=0;i+sz<=n;i++)
for(int j=0;j+sz<=n;j++)
{
sqr[sqr_cnt]=0;
for(int k=0;k<sz;k++)
for(int l=0;l<sz;l++)
sqr[sqr_cnt]^=one_sqr[i+k][j+l];
sqr_cnt++;
}
}
}
bool dfs(LL s,int step)
{
LL t=s,sel=-1;
int mind=0;
for(int i=0;i<sqr_cnt;i++)
{
if((t&sqr[i])==sqr[i])
{
mind++;t^=sqr[i];
if(sel==-1) sel=sqr[i];
}
}
if(sel==-1) return true;
if(step+mind>maxd) return false;
for(int i=1;i<=edge_cnt;i++)
{
if(sel&place(i))
if(dfs(s^place(i),step+1)) return true;
}
return false;
}
void solve()
{
LL s=((LL)1<<edge_cnt)-1;
cin>>k;
while(k--)
{
int x;
cin>>x;
s^=place(x);
}
for(maxd=0;;maxd++)
if(dfs(s,0)) break;
cout<<maxd<<endl;
}
int main()
{
cin>>t;
while(t--)
{
init();
solve();
}
return 0;
}