欢迎大家访问我的老师的OJ———caioj.cn
题面描述
思路
貌似这道题可以用DLX重复覆盖。
但是我不想写。
所以我用了
IDA*
\operatorname{IDA*}
IDA*.
这道题主要是构图有点麻烦
主要讲构图。
我们将火柴的头和尾拆开来,对于
n
∗
n
n*n
n∗n的火柴棒
我们每一行都有
2
∗
n
2*n
2∗n个点。即
s=2*n+1;/*火柴棒头和尾*/从1开始,所以要2*n+1
那么怎么将火柴棒看成边呢?。
for(int i=1;i<=s;i++)
for(int j=1;j<=s;j++)
if((i&1)!=(j&1))id[i][j]=++tot;
i&1 != j&1 (i,j)
int z=n*(n+1)*s/6;
即表示 n*n正方形之间的连边总数。
e数组表示一条边中包含d的正方形
g数组表示一个正方形中四条边的编号。
自行模拟一下。
for(int a=1;a<s;a+=2)//a为当前枚举正方形的大小
for(int i=2;i+a<=s;i+=2)
for(int j=2;j+a<=s;j+=2)
{
++tot;//j-1,i-1,j+a,i+a就是当前枚举的正方形的边界。
//实际意义应该是(i-1,j-1)\(i-1,j+a)\(i+a,j-1)\(i+a,j+a)
for(int x=0;x<=a;x+=2)
{
e[id[x+i][j-1]].push_back(tot);
e[id[x+i][j+a]].push_back(tot);
e[id[i-1][x+j]].push_back(tot);
e[id[i+a][x+j]].push_back(tot);
g[tot].push_back(id[x+i][j-1]);
g[tot].push_back(id[x+i][j+a]);
g[tot].push_back(id[i-1][x+j]);
g[tot].push_back(id[i+a][x+j]);
}
}
之后我们的估价函数也就是,暴力删掉一个正方形的所有边,并且标记这些边中的正方形,步数++,直到没有正方形。
int gj()
{
bool w[N];memcpy(w,v,sizeof(v));
int ans=0;
for(int i=1;i<=tot;i++)
{
if(w[i])
{
if(!ans)tmp=i;
++ans;
for(int j=0;j<g[i].size();j++)
{
for(int x=0;x<e[g[i][j]].size();x++)
{
w[e[g[i][j]][x]]=0;
}
}
}
}
return ans;
}
递归函数也就是,枚举现有正方形的任一条边,删掉,进入下一层即可。
bool dfs(int now)
{
int cnt=gj();
if(!cnt)return 1;
if(now+cnt>dep)return 0;
bool w[N];memcpy(w,v,sizeof(v));
int tmp0=tmp;
for(int i=0;i<g[tmp0].size();i++)
{
int st=g[tmp0][i];
for(int j=0;j<e[st].size();j++)
v[e[st][j]]=0;
if(dfs(now+1))return 1;
memcpy(v,w,sizeof(w));
}
return 0;
}
AC代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<vector>
using namespace std;
const int N=110;
int n,k,s,tot,tmp,id[16][16],dep;
vector<int>g[110],e[110];
bool v[N];
int gj()
{
bool w[N];memcpy(w,v,sizeof(v));
int ans=0;
for(int i=1;i<=tot;i++)
{
if(w[i])
{
if(!ans)tmp=i;
++ans;
for(int j=0;j<g[i].size();j++)
{
for(int x=0;x<e[g[i][j]].size();x++)
{
w[e[g[i][j]][x]]=0;
}
}
}
}
return ans;
}
bool dfs(int now)
{
int cnt=gj();
if(!cnt)return 1;
if(now+cnt>dep)return 0;
bool w[N];memcpy(w,v,sizeof(v));
int tmp0=tmp;
for(int i=0;i<g[tmp0].size();i++)
{
int st=g[tmp0][i];
for(int j=0;j<e[st].size();j++)
v[e[st][j]]=0;
if(dfs(now+1))return 1;
memcpy(v,w,sizeof(w));
}
return 0;
}
void solve()
{
scanf("%d%d",&n,&k);
s=2*n+1;/*火柴棒头和尾*/tot=0;
for(int i=1;i<=s;i++)
for(int j=1;j<=s;j++)
if((i&1)!=(j&1))id[i][j]=++tot;
for(int i=1;i<=tot;i++)e[i].clear();
int z=n*(n+1)*s/6;
for(int i=1;i<=z;i++)g[i].clear();
tot=0;
for(int a=1;a<s;a+=2)
for(int i=2;i+a<=s;i+=2)
for(int j=2;j+a<=s;j+=2)
{
++tot;
for(int x=0;x<=a;x+=2)
{
e[id[x+i][j-1]].push_back(tot);
e[id[x+i][j+a]].push_back(tot);
e[id[i-1][x+j]].push_back(tot);
e[id[i+a][x+j]].push_back(tot);
g[tot].push_back(id[x+i][j-1]);
g[tot].push_back(id[x+i][j+a]);
g[tot].push_back(id[i-1][x+j]);
g[tot].push_back(id[i+a][x+j]);
}
}
memset(v,1,sizeof(v));
for(int i=1;i<=k;i++)
{
int a;scanf("%d",&a);
for(int j=0;j<e[a].size();j++)
v[e[a][j]]=0;
}
dep=0;
while(!dfs(0))++dep;
printf("%d\n",dep);
}
int main()
{
int t;scanf("%d",&t);
while(t--)solve();
return 0;
}