DFS

其实DFS不难,理解了递归就可以很容易的理解,但是递归是入门的难度不算低,很容易被劝退

这个代码针对的是最简单的DFS题目,比如:
给定n个数字,从中选取n个按字典序进行排列

例子:

输入:123
输出:123 132 213 231 312 321

贴代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include<cstdio>
#include<iostream>
#include<cstring>

using namespace std;

bool used[7]; //记录字符是否被使用过
char keys[7], choice[7]; //keys为可选择字符,choice为已选择的字符
int counts;

int toPrint()//输出函数,依照个人喜好
{
for (int i = 0; i < strlen(keys); i++) //就是个简单的循环打印
{
cout << choice[i];
}
cout << '\n';
return 0;
}

int dfs(int nowp)
{
if (counts == strlen(keys))//在这里确认符文数量是否相等,毕竟不可能选了两个数就输出,我们要3个
{
toPrint();//调用输出函数
return 1;
}
/*
下面的循环kon控制的是每一位的字符,比如 1 1 2,因为不可能有重复数字,所以我们需要添加这个数字是否被使用过的bool数组作为标记
*/
for (int i = 0; i < strlen(keys); i++)
{
if (used[i])//确认字符是否被使用
{
continue;
}
choice[counts] = keys[i];//将未被使用的字符选进来
used[i] = true;//将当前字符标记为已使用
counts++;//位数增加
dfs(counts);//继续搜索下一位的字符,counts++就是为的这个
/*
下面的回溯我当初理解了半天,还是被卡得死死的,我觉得也是最难以理解的地方
*/
counts--;
//上面的那一层运行完后,将位数-1,因为那一层已经搜索完了,否则会造成一直调用输出函数的情况
used[i] = false;//将当前字符取消使用标记
}
return 0;//当前位数扫描完成,退出当前位置
}

int main()
{
for (int i = 0; ; i++)
{
keys[i] = getchar();
if (keys[i] == '\n') // strlen函数对于字符长度的统计需要字符数组最后一位为'\0',否则会连'\n'也当作字符长度计入
{
keys[i] = '\0';
break;
}
}
dfs(1); //这里的1代表从第一位开始排序,例如 - - - 变为 1 - - ,'-'代表尚未填入的格子
return 0;
}``

可能上面的注释很容易绕晕,我在这里手打一次过程

举个例子

比如我们要123这3个数的排列方式

当前位数:第一位

选择1并填入

现在就变成了1 - -

位数不满3位,继续下一层

当前位数:第二位

选择1,但已被使用,选择2并填入

1 2 -

位数不满3位,继续下一层

当前位数:第三位

选择1,2都被使用,填入3

1 2 3

位数满足,输出

重点:

输出完毕,退出当前位数,变为1 2 -,将3取消使用标记

当前位数:第二位

选择3并填入

1 3 -

位数不满,继续下一层

当前位数:第三位

选择1被使用,填入2

1 3 2

满足,输出,退出当前层,变为1 3 -,将2取消标记

第二层由于选择到了3,没有其他选择,故return 0退出

依此类推,人手模拟起来很简单,但是代码实现要注意很多细节

就这样吧,可能有点繁琐,如果实在论懒得想的话过几天也行就想通了,我就是这么突然想通的

对于一个刚入坑半年的萌新(还有数学56分orz)来说,有点难度,继续加油吧