洛谷 P1219 [USACO1.5]八皇后 Checker Challenge题解--zhengjun
一看题目,搜索题啊。
首先,枚举排列,然后验证是否在同一条斜线上
设有两个点是 \(i,j\)
那么如果他们在从左上到右下↘的斜线上,那么一定满足\(X_i-Y_i=X_j-Y_j\)
如果他们在从左下到右上↗的斜线上,那么一定满足\(X_i+Y_i=X_j+Y_j\)
所以打出代码:
#include<cstdio>
#include<cstring>
using namespace std;
int n;
int a[14],vis[14],cnt;
int f[30];
void dfs(int i){
if(i==n+1){
memset(f,0,sizeof(f));
for(int j=1;j<=n;j++){
if(f[j+a[j]])return;
f[j+a[j]]=1;
}
memset(f,0,sizeof(f));
for(int j=1;j<=n;j++){
if(f[j-a[j]+n])return;
f[j-a[j]+n]=1;
}
cnt++;
if(cnt<=3){
for(int j=1;j<=n;j++)printf("%d ",a[j]);
printf("\n");
}
return;
}
for(int j=1;j<=n;j++){
if(!vis[j])vis[j]=1,a[i]=j,dfs(i+1),vis[j]=a[i]=0;
}
}
int main(){
scanf("%d",&n);
dfs(1);
printf("%d",cnt);
return 0;
}
然后你会发现 \(TLE\)了
考虑优化,我们可以在放棋子的时候就把在同一斜线的给排除掉
#include<cstdio>
#include<cstring>
using namespace std;
int n;
int a[14],vis[14],cnt;
int f[30],g[30];
void dfs(int i){
if(i==n+1){
cnt++;
if(cnt<=3){
for(int j=1;j<=n;j++)printf("%d ",a[j]);
printf("\n");
}
return;
}
for(int j=1;j<=n;j++){
if(!vis[j]){
if(f[i+j])continue;
if(g[i-j+n])continue;
f[i+j]=g[i-j+n]=1;
vis[j]=1,a[i]=j,dfs(i+1),vis[j]=a[i]=0;
f[i+j]=g[i-j+n]=0;
}
}
}
int main(){
scanf("%d",&n);
dfs(1);
printf("%d",cnt);
return 0;
}