DFS(洛谷P1036 P1157 P1706)

一.什么时候用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;	
} 

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值