按常规,先说一下我自己的理解。

递归中的return常用来作为递归终止的条件,但是对于返回数值的情况,要搞明白它是怎么返回的。递归的方式就是自己调用自己,而在有返回值的函数中,上一层的函数还没执行完就调用下一层,因此,当达到递归终止条件时,首先return的是最底层调用的函数,return之后,继续执行上一层调用该函数之后的代码,此时我们看到的是上一层的情况,当上一层剩余的代码执行完之后,表示上一层的函数也结束,此时再返回上上一层,执行递归代码之后的代码,如此往复循环,直到返回到最上层,结束整个递归过程。需要注意的是,上一层执行递归之后的代码的时候,会调用下一层返回的值,也可以理解为在执行上一层代码的时候会调用下一层的实现过程,直到下一层执行完返回一个数值,然后再加上上一层的数值,就构成了上一层return的东西,如此往复。

摘自CSDN

注意这个return,return是返回上一层,而不是跳出回到主函数。

然后如果不是return,在当前层没有可以执行的东西的时候,也跳回到上一层。

下面我们来看算法笔记中的全排列和n皇后问题。

n皇后问题

n皇后问题是指在一个n*n的国际象棋棋盘上放置n个皇后,使得这n个皇后两两均不在同一行、同一列、同一对角线上,求合法的方案数。

(我第一反应这不是图论里的匹配嘛……也可以点着色(x)

因为如果枚举n*n种情况的位置,选择n个,计算量太大,所以我们只考虑全排列情况,然后剔掉不满足不在同一对角线上的情况。

法1:枚举

这里枚举出n长数列的全排列,然后剔掉不满足不在同一对角线上的情况。

全排列:给出1~n的数字,给出所有的排列方式(不重复)。(Ann)

递归思想:

  1. 递归边界:
  2. 递归本体:假设已经填好了P[1]~P[index-1],正准备填P[index]. 枚举x从1到n,如果hashtable[x] == false,就把它填到index中。然后递归下一位。

    递归完成后,把这一位的hashtable[x]释放。

判断:到达边界(输出)的时候,判断是不是在同一对角线上。

#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 11;
int n;
int P[maxn];
bool hashTable[maxn] = {false}; int cnt = 0; void show_hashTable()
{
for (int i = 1; i <= n; i++)
{
printf("%d ", hashTable[i]);
}
printf("\n");
} void generateP(int index)
{
if(index == n+1) //递归边界,边界先判断,只算结果
{
for(int i = 1; i <= n; i++)
{
printf("%d", P[i]);
}
printf("\n");
return;
// bool flag = true; //flag为true表示当前排列合法
// for(int i = 1; i <= n; i++) //遍历任意两个皇后
// {
// for(int j = i + 1; j <=n; j++)
// {
// if(abs(i - j) == abs(P[i] - P[j])) //如果在一条对角线上
// {
// flag = false; //不合法
// }
// }
// }
// if(flag) cnt++;
// return;
}
for(int x = 1; x <= n; x++)
{
printf("x %d\n", x);
if(hashTable[x] == false)
{
P[index] = x;
//show_hashTable();
hashTable[x] = true;
generateP(index + 1);
hashTable[x] = false;
//show_hashTable();
}
} } int main()
{
scanf("%d", &n);
generateP(1);
printf("%d\n", cnt); system("pause");
}

这段代码是怎么运行的?

我实在是好奇,然后就一步一步尝试了一下。

为了方便理解起见,这里选n=3.

结果是123 132 213 231 312 321

自带字典序。

 for(int x = 1; x <= n; x++)
{
printf("x %d\n", x);
if(hashTable[x] == false)
{
P[index] = x;
//show_hashTable();
hashTable[x] = true;
generateP(index + 1);
hashTable[x] = false;
//show_hashTable();
}
}

我做了一个这段代码的运行原理:

法2:回溯

定义:在到达递归前的某层,由于一些事实导致已经不需要往任何一个子问题递归,就可以直接返回上一层。

从代码编写上来看,其实就是把判断放到了递归的最开头。

#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 11;
int n;
int P[maxn];
bool hashTable[maxn] = {false}; int cnt = 0; void show_hashTable()
{
for (int i = 1; i <= n; i++)
{
printf("%d ", hashTable[i]);
}
printf("\n");
} void generateP(int index)
{
if(index == n+1) //递归边界,边界先判断,只算结果
{
for(int i = 1; i <= n; i++)
{
printf("%d", P[i]);
}
printf("\n");
cnt++;
return;
// bool flag = true; //flag为true表示当前排列合法
// for(int i = 1; i <= n; i++) //遍历任意两个皇后
// {
// for(int j = i + 1; j <=n; j++)
// {
// if(abs(i - j) == abs(P[i] - P[j])) //如果在一条对角线上
// {
// flag = false; //不合法
// }
// }
// }
// if(flag) cnt++;
// return;
}
for(int x = 1; x <= n; x++)
{
//printf("x %d\n", x);
if(hashTable[x] == false)
{
bool flag = true; //表示可行
for (int pre = 1; pre < index; pre++) //考察index之前的是否会与index冲突
{
if (abs(index - pre) == abs(x - P[pre]))
{
flag = false;
break; //已经设置了flag,很保险;break只是为了节约不要后面无意义的for循环
}
}
if (flag)
{
P[index] = x;
hashTable[x] = true;
generateP(index + 1);
hashTable[x] = false;
}
} } } int main()
{
scanf("%d", &n);
generateP(1);
printf("%d\n", cnt); system("pause");
}

【C/C++】n皇后问题/全排列/递归/回溯/算法笔记4.3的更多相关文章

  1. NQueens, NQueens2 N皇后问题,递归回溯

    N皇后的规则:任意两个皇后不在同一行,不在同一列,不在同一斜线上. 算法分析:这种问题就用回溯法.深度搜索然后回溯.用一个数组记录每一行皇后的位置,下标代表行,值代表列.对行深度搜索. public ...

  2. java暴力递归回溯算法

    今天这个问题是我之前一直想解决的,还记得以前第一次上蓝桥杯的课的时候,也就是大一高数期中模拟考试那天,下午去上蓝桥杯课,遇到这道题,当时写了写,根本没有思路,然后就给大一的模拟考试去了.印象深刻啊,一 ...

  3. LeetCode 31:递归、回溯、八皇后、全排列一篇文章全讲清楚

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天我们讲的是LeetCode的31题,这是一道非常经典的问题,经常会在面试当中遇到.在今天的文章当中除了关于题目的分析和解答之外,我们还会 ...

  4. 8皇后以及N皇后算法探究,回溯算法的JAVA实现,递归方案

    八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同 ...

  5. 回溯算法之n皇后问题

    今天在看深度优先算法的时候,联想到DFS本质不就是一个递归回溯算法问题,只不过它是应用在图论上的.OK,写下这篇博文也是为了回顾一下回溯算法设计吧. 学习回溯算法问题,最为经典的问题我想应该就是八皇后 ...

  6. JavaScript之八皇后问题(递归)

      八皇后问题,是一个古老而著名的问题,该问题最早由国际西洋棋棋手马克斯·贝瑟尔(Max Bezzel)于1848年提出.八皇后问题的具体描述为:在\(8\times8\)的国际象棋上摆放8个皇后,使 ...

  7. 3、回溯算法解题套路框架——Go语言版

    前情提示:Go语言学习者.本文参考https://labuladong.gitee.io/algo,代码自己参考抒写,若有不妥之处,感谢指正 关于golang算法文章,为了便于下载和整理,都已开源放在 ...

  8. 8皇后以及N皇后算法探究,回溯算法的JAVA实现,非递归,循环控制及其优化

    上两篇博客 8皇后以及N皇后算法探究,回溯算法的JAVA实现,递归方案 8皇后以及N皇后算法探究,回溯算法的JAVA实现,非递归,数据结构“栈”实现 研究了递归方法实现回溯,解决N皇后问题,下面我们来 ...

  9. C#数据结构与算法系列(十四):递归——八皇后问题(回溯算法)

    1.介绍 八皇后问题,是一个古老而著名的问题,是回溯算法的经典案例,该问题是国际西洋棋棋手马克斯.贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即 任意两个皇后都不能处 ...

随机推荐

  1. 『与善仁』Appium基础 — 7、ADB Shell命令的使用

    目录 1.查看进程 2.查看实时资源占用情况 3.查看进程 UID 4.其它ADB Shell命令说明 Android系统是基于 Linux 内核的,也就是说Android系统的底层是Linux系统. ...

  2. 第六周PTA笔记 括号匹配调整+堆放石子+最大积分+168

    括号匹配调整 如果通过插入" +"和" 1"可以从中得到格式正确的数学表达式,则将带括号的序列称为正确的. 例如,序列 "(())()",& ...

  3. liunx基础知识点1:系统管理相关命令、目录操作命令、文本编辑、关闭防火墙、重启和关闭

    Linux(一) liunx系统那么重要,作为一个测试人员,不掌握你就损失了好几千,为了这个钱,也为了面子,什么鬼?我爱膨胀.你看看这些知识喽.我整理的,可费工夫了. 下次给大家一个面试题啊,更直观

  4. 菜鸡的Java笔记 第二十七 - java 链表基本概念

    链表基本概念        1.链表的基本形式        2.单向链表的完整实现            认识链表        链表= 可变长的对象数组,属于动态对象数组的范畴        链表 ...

  5. 【数据结构】【图文】【oj习题】 图的拓扑排序(邻接表)

    拓扑排序: 按照有向图给出的次序关系,将图中顶点排成一个线性序列,对于有向图中没有限定次序关系的顶点,则可以人为加上任意的次序关系,由此所得顶点的线性序列称之为拓扑有序序列.显然对于有回路的有向图得不 ...

  6. 自定义 OpenShift s2i 镜像与模板——OracleJDK8

    本文目标 由于 OpenShift 官方提供的镜像与模板(OpenJDK8)不完全满足业务需要: 不包含飞行记录功能.只有 OpenJDK11 以上才被 Oracle 开源 生成堆 dump 很大很慢 ...

  7. 洛谷 P6383 -『MdOI R2』Resurrection(DP)

    洛谷题面传送门 高速公路上正是补 blog 的时候,难道不是吗/doge,难不成逆在高速公路上写题/jy 首先形成的图显然是连通图并且有 \(n-1\) 条边.故形成的图是一棵树. 我们考虑什么样的树 ...

  8. Go语言核心36讲(Go语言实战与应用二十)--学习笔记

    42 | bufio包中的数据类型 (上) 今天,我们来讲另一个与 I/O 操作强相关的代码包bufio.bufio是"buffered I/O"的缩写.顾名思义,这个代码包中的程 ...

  9. rabbit mq的安装

    rabbit mq的安装分为window的安装和linux的安装. window的安装: 1,需要安装 安装Erlang  下载地址http://www.erlang.org/downloads 我选 ...

  10. Excel-统计各分数段人数 frequency()

    FREQUENCY函数 函数名称:FREQUENCY 主要功能:以一列垂直数组返回某个区域中数据的频率分布. 使用格式:FREQUENCY(data_array,bins_array) 参数说明:Da ...