题意:传送门
题解:直接暴搜爆T这是肯定的
附上暴搜代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=10+5;
int n,k,ans[maxn][maxn],res;
bool safe(int x,int y)
{
for(int i=-1;i<=1;i++){
for(int j=-1;j<=1;j++){
if(i==0&&j==0)continue;
int nx=x+i,ny=y+j;
if(nx>=1&&nx<=n&&ny>=1&&ny<=n){
if(ans[nx][ny]){
return false;
}
}
}
}
return true;
}
void dfs(int x,int y,int cnt)
{
if(cnt==0){
res++;
return;
}
int s=n*n-x*n+y-1;
if(cnt>s){
return ;
}
if(x==n&&y==n+1)return ;
if(y==n+1){
x=x+1;y=1;
}
if(safe(x,y)){
ans[x][y]=1;
dfs(x,y+1,cnt-1);
ans[x][y]=0;
}
dfs(x,y+1,cnt);
}
int main()
{
scanf("%d%d",&n,&k);
dfs(1,1,k);
printf("%d\n",res);
return 0;
}
然后考虑用状压DP,用f[i][m][j]表示到了第i行以及i行以上一共用了m个国王,那么转移方程就是
f[i+1][p+cnt[j]][j]+=f[i][p][l] (cnt[l]<=p<=k-cnt[j])其中cnt数组,以及三个特判关系都可以打表处理下。
附上代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,k,num,all,cnt[512];
bool c1[512],c2[512][512];
ll f[10][100][512];
void pre()
{
for(int i=0;i<=all;i++){
if((i&(i>>1))==0){
num=0;
for(int j=i;j;j>>=1)num+=(j&1);
c1[i]=true;cnt[i]=num;
}
}
for(int i=0;i<=all;i++){
if(c1[i]){
for(int j=0;j<=all;j++){
if(c1[j]){
if((i&j)==0&&(i&(j>>1))==0&&(i&(j<<1))==0)c2[i][j]=true;
}
}
}
}
}
int main()
{
scanf("%d%d",&n,&k);
all=(1<<n)-1;
pre();
for(int i=0;i<=all;i++){
if(c1[i]){
f[1][cnt[i]][i]=1;
}
}
for(int i=1;i<n;i++){
for(int j=0;j<=all;j++){
if(c1[j]){
for(int l=0;l<=all;l++){
if(c1[l]&&c2[j][l]){
for(int p=cnt[j];p+cnt[l]<=k;p++)f[i+1][p+cnt[l]][l]+=f[i][p][j];
}
}
}
}
}
ll ans=0;
for(int i=0;i<=all;i++)ans+=f[n][k][i];
printf("%lld\n",ans);
return 0;
}