八皇后问题
这里我要感谢b站小姐姐的讲解,讲的真的超棒的,我能顺利地做出来就靠这个视频了。
-
问题解决的关键点
- 回溯
- 棋盘存储
- 攻击范围
-
dfs核心递归函数
k==n 表示找到一组解 打印
在一层循环判断是否可以放置皇后,如果可以进行以下操作(按列):
- 备份attack数组(备份后,最后恢复)
- 标记该位置为Q(2. 存储位置)
queue[k][i]='Q'
(仅改变一个地方,最后直接改回来) - 上一步放置了皇后,所以更新attack数组
- 递归试探k+1行的皇后位置(按行)
- 递归完成后,恢复attack数组和
queue[k][i]='.'
-
代码总览
/* 八皇后问题 */ #include<stdio.h> int ack[10][10]; char que[10][10]; int cnt=0; void init (int n);//初始化 void print(int n);//数组的打印 void copy(int a[10][10],int b[10][10],int n);//把a数组拷贝到b数组 void dfs(int k,int n);//核心递归算法 void update_ack(int x,int y,int n);//更新ack数组 int main() { int n; scanf("%d",&n); init(n); dfs(0,n); printf("cnt = %d\n",cnt); return 0; } void init (int n){ for(int i=0;i<n;i++) for(int j=0;j<n;j++){ ack[i][j]=0; que[i][j]='.'; } } void print(int n){ for(int i=0;i<n;i++){ for(int j=0;j<n;j++) printf("%c ",que[i][j]); printf("\n"); } printf("\n"); } void dfs(int k,int n){ // k==n 表示找到一组解 打印 if(k==n){ print(n); cnt++; return; } for(int i=0;i<n;i++){ // 在一层循环判断是否可以放置皇后,如果可以进行以下操作(按列): if(ack[k][i]==0){ // 1. 备份attack数组(备份后,最后恢复) int tmp[10][10]; copy(ack,tmp,n); // 2. 标记该位置为Q(2. 存储位置)`queen[k][i]='Q'` (仅改变一个地方,最后直接改回来) que[k][i]='Q'; // 3. 上一步放置了皇后,所以更新attack数组 update_ack(k,i,n); // 4. 递归试探k+1行的皇后位置(按行) dfs(k+1,n); // 5. 递归完成后,恢复attack数组和 `queen[k][i]='.' ` copy(tmp,ack,n); que[k][i]='.'; } } } void copy(int a[10][10],int b[10][10],int n){ for(int i=0;i<n;i++) for(int j=0;j<n;j++) b[i][j]=a[i][j]; } void update_ack(int x,int y,int n){ int dx[]={-1,-1,-1,0, 1, 1, 1, 0}; int dy[]={-1,0, 1, 1, 1, 0,-1,-1}; ack[x][y]=1; for(int i=1;i<=n-1;i++)//从1延伸到n-1的距离 for(int j=0;j<8;j++){//从八个方向延伸 int nx=x+i*dx[j]; int ny=y+i*dy[j]; if(nx>=0&&nx<n&&ny>=0&&ny<n) ack[nx][ny]=1; } }
-
测试结果