一.什么时候用DFS
DFS常用于解决所有解,即全排列的问题。
二.DFS格式(模版)
此处i的初始值有两种取法:
1.i=1。此时是全排列,包含乱序(即非字典序输出),共有n!个解 。
void dfs(int step)
{
if (判断条件:一般为是否到最后一步)
{
输出答案;
return; //此处的return是退回到上一级dfs(即最近一次调用dfs的地方,而不是直接退回
到主函数mian当中!!!)
}
for (i=1;i<=n;i++)
{
if(book[i]==1) //如果该数未被使用
{
a[step]=i; //i是具体的数字,step是第几个位置
book[i]=0; //该数已被使用
dfs(step+1);
book[i]=1; //恢复
}
}
return; //此处逐步退回上一级调用,最后一次是返回主函数
}
2.i=startx。该startx指一个特定的值,通常为上一级dfs起始值加1
void dfs(int step,int startx) //startx为每一次循环i的初始值
{
int i;
if (到最后一步)
{
输出结果;
return;
}
for (i=startx;i<=n;i++)
{
sum+=a[i]; //需执行的语句
dfs(step+1,i+1); //i当前的值加1赋给startx,则下一级dfs中的for循环就从上一级的
i后一个值开始,即为升序(字典序),可理解为不降原则,共有
Cnn个解(不会出现321这种,这是降序)
}
return;
}
两种赋值的区别:
第一种为递推+回溯。
第二种仅为递推,没有回溯,因为本身就不是全排列不需要输出所有解,同时也不需要用book去标记某数是否使用过,因为对于每一组解来说,每个位置上的数永远在前面一个位置上的数的后面,不存在像回溯一样某个数会有取出再放的问题,因此book标记是否使用可省略。注意此方法dfs函数里需要定义两个变量!!!
三.例题
1.洛谷1706(纯模版题)
#include<stdio.h>
int n;
int a[10],book[10];
void dfs(int step)
{
int i;
if (step>n)
{
for (i=1;i<=n;i++)
printf("%5d",a[i]);
printf("\n");
return;
}
for (i=1;i<=n;i++)
{
if (book[i]==1)
{
a[step]=i;
book[i]=0;
dfs(step+1);
book[i]=1;
}
}
return;
}
int main()
{
int i;
scanf("%d",&n);
for (i=0;i<=9;i++)
book[i]=1;
dfs(1);
return 0;
}
2.洛谷P1036
#include<stdio.h>
long long ans;
int sum=0,t;
int n,k;
int i;
int a[25];
int prime (int a)
{
int i;
for (i=2;i*i<=a;i++)
{
if (a%i==0)
return 0;
}
return 1;
}
void dfs(int step,int startx)
{
int sum=0;
int i;
if (step>k)
{
if (prime(sum)==1)
ans+=1;
return;
}
for (i=startx;i<=n;i++)
{
sum+=a[i];
dfs(step+1,i+1);
}
return;
}
int main()
{
scanf("%d %d",&n,&k);
for (i=1;i<=n;i++)
scanf("%d",&a[i]);
dfs(1,1);
printf("%d",ans);
return 0;
}