前言
忘带课本了,记一下课本上的内容,不然等还书就忘记了。
深度优先搜索
输入一个数n,输出1~n的全排列。转换成模型就是编号1,2,3的扑克牌放到1,2,3的盒子中去,每个盒子只放一张牌,一共有多少种不同的放法。我们先走到1号盒子前面,规定从1号扑克牌依次放入,所以把1号扑克牌放进1号盒子,然后走到2号盒子前面。按照规定的顺序,2号扑克牌放在2号盒子,3放3号盒子。此时生成了一种排列就是“1,2,3”。然后开始返回。走到第三个盒子,拿出3号牌,但是手上只有三号牌,没有其他选择,所以不放新的牌,再走到2号盒子拿出2号牌,此时手里有2,3号牌,我们选择3号放入2号盒子,2号放入3号盒子,此时又生成了一个新的排列“1 3 2”如此循环下去,我们能够得到所有的排列。
代码如下(示例):
//用一个for循环就可以解决
for (i = 1; i <= n; i++) {
a[step] = i;//将i号扑克牌放入第step个盒子中
}
比如说1号已经放入盒子中,那么下次放扑克牌的时候就不能再放1号了,因为手里已经没有1号牌了。因此我们应该用一个数组book来标记已经使用过的扑克牌
for (i = 1; i <= n; i++) {
if(book[i]==0) {//扑克牌还没有被使用
a[step] = i;//将i号扑克牌放入第step个盒子中
book[i] = 1;//此时手里已经没有这张牌了
}
}
我们已经处理完这step个盒子了,继续往下是第step+1个盒子,此时设置一个函数,用递归调用此函数即可
void DFS(int step) //step表示现在站在的第几个盒子面前
{
for (i = 1; i <= n; i++) {
if(book[i]==0) {//扑克牌还没有被使用
a[step] = i;//将i号扑克牌放入第step个盒子中
book[i] = 1;//此时手里已经没有这张牌了
DFS(step + 1);//递归调用DFS函数
book[i] = 0;//非常关键的一步,只用把用过的扑克牌先收回来,才能继续使用
}
}
return;
}
我们发现,当处理到第n+1个盒子时,前面n个盒子已经全部处理完毕,此时将扑克牌的编号打印出来即可。注意:打印完毕要立即return,不然就没法重新调用DFS函数了
void DFS(int step) //step表示现在站在的第几个盒子面前
{
if (step == n + 1)//表示现在站在第n+1个盒子面前,前面n个盒子已经放好了
{
//输出一种排列
for (i = 1; i <= n; i++)
printf("%d", a[i]);
printf("\n");
return;//返回前一步(最近一次调用DFS函数的地方)
}
for (i = 1; i <= n; i++) {
if(book[i]==0) {//扑克牌还没有被使用
a[step] = i;//将i号扑克牌放入第step个盒子中
book[i] = 1;//此时手里已经没有这张牌了
DFS(step + 1);//递归调用DFS函数
book[i] = 0;//非常关键的一步,只用把用过的扑克牌先收回来,才能继续使用
}
}
return;
}
完整代码
#include<stdio.h>
int a[10], book[10], n;
void DFS(int step) //step表示现在站在的第几个盒子面前
{
int i;
if (step == n + 1)//表示现在站在第n+1个盒子面前,前面n个盒子已经放好了
{
//输出一种排列
for (i = 1; i <= n; i++)
printf("%d", a[i]);
printf("\n");
return;//返回前一步(最近一次调用DFS函数的地方)
}
for (i = 1; i <= n; i++) {
if(book[i]==0) {//扑克牌还没有被使用
a[step] = i;//将i号扑克牌放入第step个盒子中
book[i] = 1;//此时手里已经没有这张牌了
DFS(step + 1);//递归调用DFS函数
book[i] = 0;//非常关键的一步,只用把用过的扑克牌先收回来,才能继续使用
}
}
return;
}
int main()
{
scanf_s("%d", &n);//注意输入1到9之间的整数
DFS(1);//首先站在1号盒子面前
getchar();
getchar();
return 0;
}
总结
这个例子是深度优先搜索(Depth First Search,DFS)的基本模型。
关键在于解决现在该干什么,这就需要用到递归调用。
基本模型如下:
void DFS(int step)
{
判断边界
尝试每一种可能 for (i = 1; i <= n; i++)
{
继续下一步 DFS(step + 1);
}
返回
}
每一种尝试就是一种“扩展”。每一次站在一个盒子面前的时候,其实都有n种扩展方法,但并不是每种扩展方法都能成功。