1.练习项目:
问题描述
给定一个 n×n 的棋盘。现在要向棋盘中放入 n 个黑皇后和 n 个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。
问总共有多少种放法?
输入格式
输入的第一行包含一个整数 n。
输出格式
输出一行包含一个整数,表示答案。
2.选择课程
在蓝桥云课中选择题库,选择题号17013并开始练习。
3.开始练习
(1)源码 :
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=15;
ll n,ans;
ll vis_b[N][N],vis_w[N][N];
bool pos[N][N];
void dfs_w(int dep)
{
if(dep==n+1){
ans++;
return;
}
for(int i=1;i<=n;i++){
if(vis_w[dep][i])continue;
if(pos[dep][i])continue;
for(int j=1;j<=n;j++)vis_w[j][i]++;
for(int k=i,t=dep;k<=n&&t<=n;k++,t++)vis_w[t][k]++;
for(int k=i,t=dep;k>=1&&t>=1;k--,t--)vis_w[t][k]++;
for(int k=i,t=dep;k<=n&&t>=1;k++,t--)vis_w[t][k]++;
for(int k=i,t=dep;k>=1&&t<=n;k--,t++)vis_w[t][k]++;
dfs_w(dep+1);
for(int j=1;j<=n;j++)vis_w[j][i]--;
for(int k=i,t=dep;k<=n&&t<=n;k++,t++)vis_w[t][k]--;
for(int k=i,t=dep;k>=1&&t>=1;k--,t--)vis_w[t][k]--;
for(int k=i,t=dep;k<=n&&t>=1;k++,t--)vis_w[t][k]--;
for(int k=i,t=dep;k>=1&&t<=n;k--,t++)vis_w[t][k]--;
}
}
void dfs_b(int dep) {
if(dep == n+1) {
dfs_w(1);
return;
}
for(int i = 1; i <= n; i++) {
if(vis_b[dep][i]) continue;
pos[dep][i] = true;
for(int j = 1; j <= n; j++)vis_b[dep][j]++,vis_b[j][i]++;
for(int k=i,t=dep; k<=n&&t<=n; k++,t++) vis_b[t][k]++;
for(int k=i,t=dep; k>=1&&t>=1; k--,t--) vis_b[t][k]++;
for(int k=i,t=dep; k<=n&&t>=1; k++,t--) vis_b[t][k]++;
for(int k=i,t=dep; k>=1&&t<=n; k--,t++) vis_b[t][k]++;
dfs_b(dep + 1);
pos[dep][i] = false;
for(int j = 1; j <= n; j++)vis_b[dep][j]--,vis_b[j][i]--;
for(int k=i,t=dep; k<=n&&t<=n; k++,t++) vis_b[t][k]--;
for(int k=i,t=dep; k>=1&&t>=1; k--,t--) vis_b[t][k]--;
for(int k=i,t=dep; k<=n&&t>=1; k++,t--) vis_b[t][k]--;
for(int k=i,t=dep; k>=1&&t<=n; k--,t++) vis_b[t][k]--;
}
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
dfs_b(1);
cout<<ans<<'\n';
return 0;
}
(2)检验结果
对此代码进行检验,检验后无报错,提交此代码,判题结果为正确90分,发现最后一个案例超时,对源代码进行优化,优化过后的代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N = 15;
int n, cnt = 0; // cnt: 单色皇后解的数量
int pos[3000][N]; // pos[k][i] 表示第k个解中第i行皇后所在的列
int vis[N][N]; // 攻击标记
int loc[N]; // 当前解的各行皇后列位置
void dfs(int dep) {
if (dep == n + 1) {
cnt++;
for (int i = 1; i <= n; i++)
pos[cnt][i] = loc[i];
return;
}
for (int i = 1; i <= n; i++) {
if (vis[dep][i]) continue;
loc[dep] = i;
// 标记攻击范围(保留你熟悉的二维标记方式)
for (int j = 1; j <= n; j++) vis[dep][j]++, vis[j][i]++;
for (int k = i, t = dep; k <= n && t <= n; k++, t++) vis[t][k]++;
for (int k = i, t = dep; k >= 1 && t >= 1; k--, t--) vis[t][k]++;
for (int k = i, t = dep; k <= n && t >= 1; k++, t--) vis[t][k]++;
for (int k = i, t = dep; k >= 1 && t <= n; k--, t++) vis[t][k]++;
dfs(dep + 1);
// 回溯
for (int j = 1; j <= n; j++) vis[dep][j]--, vis[j][i]--;
for (int k = i, t = dep; k <= n && t <= n; k++, t++) vis[t][k]--;
for (int k = i, t = dep; k >= 1 && t >= 1; k--, t--) vis[t][k]--;
for (int k = i, t = dep; k <= n && t >= 1; k++, t--) vis[t][k]--;
for (int k = i, t = dep; k >= 1 && t <= n; k--, t++) vis[t][k]--;
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n;
dfs(1);
int ans = 0;
for (int i = 1; i <= cnt; i++) { // 枚举黑皇后解
for (int j = 1; j <= cnt; j++) { // 枚举白皇后解
bool ok = true;
for (int r = 1; r <= n; r++) { // 检查每一行是否同列(同格)
if (pos[i][r] == pos[j][r]) {
ok = false;
break;
}
}
if (ok) ans++;
}
}
cout << ans << '\n';
return 0;
}
对此代码进行检验,检验后无报错,提交此代码,判题结果为正确100分。
(3)练习心得:注意每段代码末尾的分号是否存在,如不存在则需即使补充;输入法是否切换 为英语模式;语法是否错误。