题目描述

检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。



上面的布局可以用序列2 4 6 1 3 5来描述,第i个数字表示在第i行的相应位置有一个棋子,如下:

行号 1 2 3 4 5 6

列号 2 4 6 1 3 5

这只是跳棋放置的一个解。请编一个程序找出所有跳棋放置的解。并把它们以上面的序列方法输出。解按字典顺序排列。请输出前3个解。最后一行是解的总个数。

输入输出格式

输入格式:

一个数字N (6 <= N <= 13) 表示棋盘是N x N大小的。

输出格式:

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

思路

首先是如何描述题目,可以借助数组的索引为行,对应值为列,如此行必定不会重复,然后对列的可能的值进行全排列(这样行列均不会重复),找出可以满足对角线不平行的组合

经典问题,使用普通的dfs搜索全部路径,也就是搜索到最底层,简单容易理解但是耗时久,优化的思路是到达新的一层直接对新入单位进行判断,满足进入下一层,不满足则结束当前路径

TLE代码(普通dfs,耗时久)

#include<cstdio>
#include<cmath>
using namespace std;
int num = 0;//全排列数字的最大值
int hash[14] = {0};//是否已经选择的标志,0未选,1已选
int nums[14] = {0};//存储需要全排列的数字
int results[14]={0};//搜索过程中记录的全排列的值
int temp =0;//满足条件的个数
void dfs(int depth) {
if (depth == num+1) {
for (int i = 1; i < num; ++i) {
for (int j = i+1; j <= num; ++j) {
if(abs(results[j]-results[i])==abs(j-i)){
return;
}
}
}
if(temp<3){
for (int k = 1; k <= num; ++k) {
printf("%d ",results[k]);
}
printf("\n");
}
temp++;
return;
} for (int j = 1; j <= num; ++j) {
if(hash[j]==0){
results[depth]=nums[j];
hash[j]=1;
dfs(depth+1);
hash[j]=0;
}
}
}
int main() {
scanf("%d",&num);
for (int i = 1; i <= num; ++i) {
nums[i]=i;
}
dfs(1);
printf("%d",temp);
return 0;
}

AC1(回溯dfs)

#include<cstdio>
#include<cmath> using namespace std;
int num = 0;//全排列数字的最大值
int hash[14] = {0};//是否已经选择的标志,0未选,1已选
//int nums[14] = {0};//存储需要全排列的数字,可以不使用
int results[14]={0};//搜索过程中记录的全排列的值
int temp =0;//满足条件的个数
//回溯版本
void dfs(int depth) {
//判断新入的是否满足,不满足直接回退到上一层
//当前深度为depth,数组最大索引为depth-1,而新入的值与前面的值进行比较,所以i < depth-1
for (int i = 1; i < depth - 1; ++i) {
int left = abs(results[depth - 1] - results[i]);
int rigth = abs(depth - 1 - i);
if (left == rigth) {
return;
}
}
//若到达最后这一层,一定是满足的
if (depth == num + 1) {
if(temp<3){
for (int k = 1; k <= num; ++k) {
printf("%d ", results[k]);
}
printf("\n");
}
temp++;
return;
}
//下一层的入口
for (int j = 1; j <= num; ++j) {
if (hash[j] == 0) {
//results[depth] = nums[j];等价
results[depth] = j;
hash[j] = 1;
dfs(depth + 1);
hash[j] = 0;
}
}
}
int main() {
scanf("%d", &num);
// for (int i = 1; i <= num; ++i) {
// nums[i] = i;
// }
dfs(1);
printf("%d", temp);
return 0;
}

稍微优化(更直观)

#include<cstdio>
#include<cmath>
using namespace std;
int num = 0;
int hash[14] = {0};
int results[14] = {-1};
int ans = 0;
//回溯版本
void dfs(int depth) {
if (depth == num + 1) {
if(ans<3){
for (int k = 1; k <= num; ++k) {
printf("%d ", results[k]);
}
printf("\n");
}
ans++;
return;
}
for (int j = 1; j <= num; ++j) {
bool flag = true;
if (hash[j] == 0) {
//回溯,不能取最后一个
for (int i = 1; i < depth ; ++i) {
// |y1 - y2| = |x1 - x2|
if (abs(j - results[i]) == abs(depth - i)) {
flag = false;
break;
}
}
if(flag){
results[depth] = j;
hash[j] = 1;
dfs(depth + 1);
hash[j] = 0;
}
}
}
}
int main() {
scanf("%d", &num);
dfs(1);
printf("%d", ans);
return 0;
}

学到的点

1 回溯是dfs的一种优化方式

2 理解dfs的关键在于理解栈的调用,(形象化的比喻搜索的过程,就是一层一层执行函数)

搜索--P1219 N皇后的更多相关文章

  1. 洛谷 P1219 八皇后【经典DFS,温习搜索】

    P1219 八皇后 题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序 ...

  2. 搜索6--noi1700:八皇后问题

    搜索6--noi1700:八皇后问题 一.心得 二.题目 1756:八皇后 查看 提交 统计 提问 总时间限制:  1000ms 内存限制:  65536kB 描述 会下国际象棋的人都很清楚:皇后可以 ...

  3. 搜索5--noi1700:八皇后问题

    搜索5--noi1700:八皇后问题 一.心得 二.题目 1700:八皇后问题 查看 提交 统计 提问 总时间限制:  10000ms 内存限制:  65536kB 描述 在国际象棋棋盘上放置八个皇后 ...

  4. P1219 N皇后

    P1219 N皇后 题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序 ...

  5. 洛谷 P1219八皇后

    把全部,在这251秒,赌上! ——<游戏人生zero> 题目:https://www.luogu.org/problem/P1219 八皇后是一道非常非常非常经典的深搜+回溯的题目. 这道 ...

  6. 【搜索】P1219 八皇后

    题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序列2 4 6 1 3 ...

  7. 洛谷 p1219 八皇后

    刚参加完蓝桥杯 弱鸡错了好几道..回头一看确实不难 写起来还是挺慢的 于是开始了刷题的道路 蓝桥杯又名搜索杯 暴力杯...于是先从dfs刷起 八皇后是很经典的dfs问题 洛谷的这道题是这样的 上面的布 ...

  8. P1219 八皇后 含优化 1/5

    题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序列2 4 6 1 3 ...

  9. luogu p1219 八皇后

    https://www.luogu.org/problem/show?pid=1219 经典问题,搜索一遍过. 重点是判断皇后能否在map[x][y]放下的条件 因为是dfs的时候过程中 x 是递增的 ...

随机推荐

  1. BZOJ 1037: [ZJOI2008]生日聚会Party 四维DP

    1037: [ZJOI2008]生日聚会Party Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1650  Solved: 971[Submit][ ...

  2. Android开发之接收系统广播消息

    BroadcastReceiver除了接收用户所发送的广播消息之外.另一个重要的用途:接收系统广播. 假设应用须要在系统特定时刻运行某些操作,就能够通过监听系统广播来实现.Android的大量系统事件 ...

  3. go14--并发concurrency,Goroutine ,channel

    package main /** 并发concurrency 很多人都是冲着 Go 大肆宣扬的高并发而忍不住跃跃欲试,但其实从 源码的解析来看,goroutine 只是由官方实现的超级“线程池”而已. ...

  4. ReSharper warns: “Static field in generic type”

    http://stackoverflow.com/questions/9647641/resharper-warns-static-field-in-generic-type It's fine to ...

  5. cordova常用命令

    安装 cordova: npm install -g cordova 创建应用程序 cordova create hello com.example.hello HelloWorld 添加平台 cor ...

  6. poj 3621(最优比率环)

    Sightseeing Cows Farmer John has decided to reward his cows for their hard work by taking them on a ...

  7. Java工作中常用到的工具

    刚看但网上一篇Java最流行工具的文章,结合自己日常应用总结一下开发工作中常用到的工具. 一,Java版本,jdk8,也是Java普及最快的版本,除了本身性能提升外,新增的函数式编程特性也让开发效率更 ...

  8. E2017614-hm

     pluck   n. 勇气,精神; 内脏; 快而猛的拉; 〈俚〉不及格;   vt. 拔掉; 采,摘; 鼓起(勇气等); 弹(乐器);  scope  n. (处理.研究事务的) 范围; 眼界,见识 ...

  9. [TYVJ1391]走廊泼水节

    Description 话说,中中带领的OIER们打算举行一次冬季泼水节,当然这是要秘密进行的,绝对不可以让中中知道.不过中中可是老江湖了,当然很快就发现了我们的小阴谋,于是他准备好水枪迫不及待的想要 ...

  10. 2017杭电多校第五场Rikka with Subset

    Rikka with Subset Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others ...