思想是:把数存进一个数组a,每一位抽出,每抽出这个数就把对应的标记(用一个book数组),在递归时不再鸟它
其实因为每一次要做的步骤都是一样的,所以只需写一次的步骤,再递归即可。
#include <stdio.h>
#include <string.h>
int a[100];
int visite[100];
int n;
void dfs(int k)
{
if(k==n+1)
{
for(int i=1;i<=n;i++)
printf("%d ",a[i]);
printf("\n");
return;
}
for(int j=1;j<=n;j++)
{
if(visite[j]==0)
{
visite[j] = 1;
a[k] = j;//试探
dfs(k+1);
visite[j] = 0;//回溯
}
}
}
int main()
{
while(~scanf("%d",&n))
{
memset(visite,0,sizeof(visite));
memset(a,0,sizeof(a));
dfs(1);
}
}
此类题目基本模型为:
void dfs()
{
1.判断递归出口
/*利用循环尝试每一种可能,但不同于暴力搜索这种低端操作QAQ*/
2.for(){A.执行操作 B.回溯dfs(k+1)}
}
----------------------华丽的分割--------------------------
下面为某一实例:输入一个n,再输入n个数,对这n个数列出所有的组合可能
#include <stdio.h>
#include <string.h>
int a[15];//输入的数
int store[5];
int flag[15];//标记
int n;
void DFS(int t)//深度搜索
{
int i;
if(t==3)//很需要理解的一点是为什么运行出来第一个是123 第二个是124
{
for(i=0;i<t;i++)//是因为1 2 3到3的时候满足t=3了输出123满足之后归返回直接先把visite[3]置零而for循环还没结束
printf("%d",store[i]);//把4赋值给了
printf("\n");
return;
}
for(i=0;i<n;i++)
{
if(flag[i]==0)
{
store[t] = a[i];
flag[i] = 1;//这个已经用过了,标记掉,这样在递归的时候就不会搜索到它了
DFS(t+1);//递归操作
flag[i] = 0;//经过调试发现,如果没有这条语句的话,输入3 1 2 3 只会出现一组123
/*里置零的原因是当最后一次递归结束的时候,要逐一返回前面的递归调用去执行还未执行完的语句,此处置零就是把之前的标记删除,让前面的数可以再和新的数组合*/
}
}
}
int main()
{
int i;
while(scanf("%d",&n)&&n!=0)
{
memset(flag,0,sizeof(flag));
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
for(i=0;i<n;i++)
{
if(a[i]!=0)
{
store[0] = a[i];//第一个数直接存
flag[i] = 1;//此数已存就标记起立
DFS(1);//调用,已经存了一个从t=1开始
flag[i] = 0;
}
}
}
return 0;
}
下面为摘自某博客对递归的理解:
递归通常用来解决结构自相似的问题。所谓结构自相似,是指构成原问题的子问题与原问题在结构上相似,
可以用类似的方法解决。具体地,整个问题的解决,可以分为两部分:
第一部分是一些特殊情况,有直接的解法;第二部分与原问题相似,但比原问题的规模小。
实际上,递归是把一个不能或不好解决的大问题转化为一个或几个小问题,再把这些小问题进一步分解成更小的问题,直至每个小问题都可以直接解决。因此,递归有两个
基本要素:(1)边界条件:确定递归到何时终止,也称为递归出口。
(2)递归模式:大问题是如何分解为小问题的,也称为递归体。递归函数只有具备了这两个要素,才能在有限次计算后得出结果
[摘自](https://www.cnblogs.com/qiaogaojian/p/5866511.html)