1、先从多重循环谈起
123的全排列
#include <bits/stdc++.h>
using namespace std;
int main(){
int sum=0;
for(int a=1;a<=3;a++)
for(int b=1;b<=3;b++)
for(int c=1;c<=3;c++)
if(a!=b&&a!=c&&b!=c) sum++;
cout<<sum<<endl;
return 0;
}
如果输入一个数n,输出1-n的全排列, 就需要n个循环进行枚举。n重循环,n是变量不容易编写程序,可以使用递归完成程序的编写。
2、引入递归,开始解决问题
考虑递归终止条件的写法
#include <bits/stdc++.h>
using namespace std;
int a[101];
int sum = 0;
int n = 0;
bool is_num() { //判断所有的数都不重复
bool flag = 1;
int book[101];
memset(book, 0, sizeof(book));
for (int i = 1; i <= n; i++)
book[a[i]] = 1;
for (int i = 1; i <= n; i++)
if (book[i] == 0) flag = 0;
return flag;
}
void fun(int b) {
if (b == 0 ) return; //递归终止
for (int i = 1; i <= n; i++) { //枚举当前位上可能的数
a[b] = i;
if (b == 1 && is_num() != 0) { //满足要求,种类加一,打印当前种类
sum++;
for (int j = 1; j <= n; j++) cout << a[j] << " ";
cout << endl;
}
fun(b - 1);
}
}
int main() {
cin >> n;
fun(n);
cout << sum << endl;
return 0;
}
考虑递归最后一层的写法
#include <bits/stdc++.h>
using namespace std;
int a[101];
int sum = 0;
int n = 0;
bool is_num() { //判断所有的数都不重复
bool flag = 1;
int book[101];
memset(book, 0, sizeof(book));
for (int i = 1; i <= n; i++)
book[a[i]] = 1;
for (int i = 1; i <= n; i++)
if (book[i] == 0) flag = 0;
return flag;
}
void fun(int b) {
if (b == 1) {
for (int i = 1; i <= n; i++) { //枚举当前位上可能的数
a[b] = i;
if (is_num() != 0) { //满足要求,种类加一,打印当前种类
sum++;
for (int j = 1; j <= n; j++) cout << a[j] << " ";
cout << endl;
}
}
} else {
for (int i = 1; i <= n; i++) { //枚举当前位上可能的数
a[b] = i;
fun(b - 1);
}
}
}
int main() {
cin >> n;
fun(n);
cout << sum << endl;
return 0;
}
带标志位的写法,避免前面的数据重复
#include <bits/stdc++.h>
using namespace std;
int a[101];
int sum = 0;
int n = 0;
int book[101];
void fun(int b) {
if (b == 0) {
sum++;
for (int j = 1; j <= n; j++) cout << a[j] << " ";
cout << endl;
return;
}
for (int i = 1; i <= n; i++) { //枚举当前位上可能的数
if (book[i] != 0) continue;
else book[i]++;
a[b] = i;
fun(b - 1);
book[i]--; //当前情况不满足时,需要把当前的标志清除掉
}
}
int main() {
cin >> n;
fun(n);
cout << sum << endl;
return 0;
}
3、深度搜索的基本思想:
首先判断递归是否可以终止,不可以的情况下将当前层可能的情况进行罗列(枚举与搜索),如果数据与前面的数据不冲突,记录下当前层的数据,递归进入下层搜索,完成下层搜索后,需要将本层的数据复原,重新选值进行搜索。
将当前层可能的情况进行罗列(枚举与搜索),如果数据与前面的数据不冲突,记录下当前层的数据,判断是否是最下一层的搜索,是的话将满足条件的数据进行输出,不是的话递归进入下层搜索,完成下层搜索后,需要将本层的数据复原,重新选值进行搜索。
4、广度搜索的基本思想
#include <bits/stdc++.h>
using namespace std;
struct node {
int data;
int depth;
int f;
};
struct node que[1001];
int main() {
int head, tail;
int n;
cin >> n;
//初始队列 假使起始点为0,深度为0
head = tail = 1;
que[tail].data = 0;
que[tail].depth = 0;
que[tail].f = 0;
tail++;
//广搜进行数据填充
while (head < tail) {
for (int i = 1; i <= n; i++) {
//加入条件,组合问题无法建立与上一步的关系
//此处将所有结果进行添加,在读取时进行判断
que[tail].data = i;
que[tail].depth = que[head].depth + 1;
que[tail].f = head;
// cout << que[tail].depth << endl;
tail++;
}
head++;
if (que[head].depth == n) break;
}
//读取结果,进行判断输出
int *book = (int*)malloc((n + 1) * sizeof(int));
int *data1 = (int*)malloc((n + 1) * sizeof(int));
for (int i = 1; i <= n; i++) book[i] = 0;
tail--;
int sum=0;
while (que[tail].depth == n) {
//先检查数据是否有重复
int flag = 1;
for (int i = 1; i <= n; i++) book[i] = 0;
data1[que[tail].depth] = que[tail].data;
book[que[tail].data] = 1;
int next = que[tail].f;
while (que[next].f != 0) {
data1[que[next].depth] = que[next].data;
if (book[que[next].data] == 1) {
flag = 0;
break;
}
book[que[next].data] = 1;
next = que[next].f;
}
if (flag) {
for (int i = 1; i <= n; i++)
cout << data1[i] << " ";
cout << endl;
sum++;
}
tail--;
}
cout<<sum;
return 0;
}
定义一个队列用来存储所有的数据,广度搜索一般从一个点开始扩展,我们假设开始有个0就可以了,从0开始扩展1-n,再从1-n的每个数进行下一层的扩展,在扩展下一层时需要对数据进行判断,该数据是否已经重复,此处没法一个可行结果从头到尾的拓展,所以先将所有结果拓展到队列中,使用深度和父节点的标志,从下到上寻找正确结果(有点难)。